home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ops5c.zip / OPS5C.DOC < prev    next >
Text File  |  1990-05-22  |  117KB  |  3,037 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.                               OPS5c User's Guide
  18.  
  19.                                 Version 1.08a
  20.  
  21.                         For the Amiga Personal Computer
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.                              Bernie J. Lofaso, Jr.
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.                                Table of Contents
  74.  
  75.        1.  Introduction.............................................4
  76.          1.1  What is OPS5c?........................................4
  77.          1.2  OPS5 History..........................................4
  78.          1.3  Production Systems Overview...........................5
  79.        2.  Working Memory...........................................9
  80.          2.1  Class Declarations....................................9
  81.          2.2  Working Memory Element Structure......................9
  82.          2.3  Vector Attributes....................................10
  83.        3.  Rules...................................................12
  84.          3.1  Rule Structure.......................................12
  85.        4.  The LHS.................................................13
  86.          4.1  Condition Elements...................................13
  87.          4.2  Variables............................................13
  88.          4.3  Quoting..............................................13
  89.          4.4  Predicates...........................................14
  90.          4.5  Conjuctions..........................................14
  91.          4.6  Disjunctions.........................................15
  92.          4.7  Negated Condition Elements...........................15
  93.          4.8  Element Variables....................................16
  94.        5.  The RHS.................................................17
  95.          5.1  Element Designators..................................17
  96.          5.2  RHS Patterns.........................................17
  97.          5.3  Pre-defined Functions................................18
  98.             5.3.1  genatom.........................................18
  99.             5.3.2  litval..........................................18
  100.             5.3.3  substr..........................................18
  101.             5.3.4  compute.........................................18
  102.             5.3.5  accept..........................................19
  103.             5.3.6  acceptline......................................19
  104.          5.4  RHS Actions..........................................19
  105.             5.4.1  make............................................20
  106.             5.4.2  remove..........................................20
  107.             5.4.3  modify..........................................20
  108.             5.4.4  write...........................................21
  109.             5.4.5  bind............................................21
  110.             5.4.6  cbind...........................................21
  111.             5.4.7  call............................................22
  112.             5.4.8  halt............................................22
  113.             5.4.9  openfile........................................22
  114.             5.4.10  closefile......................................22
  115.             5.4.11  default........................................22
  116.        6.  Conflict Resolution.....................................24
  117.        7.  OPS5 Programming........................................26
  118.        8.  Top Level Commands......................................29
  119.          8.1  include..............................................29
  120.          8.2  run..................................................30
  121.          8.4  ppwm.................................................30
  122.          8.5  wm...................................................30
  123.          8.6  cs...................................................31
  124.          8.7  strategy.............................................31
  125.          8.8  pbreak...............................................31
  126.          8.9  dump.................................................31
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.          8.8  size.................................................31
  140.        9.  The OPS5c System........................................32
  141.          9.1  Installing OPS5c.....................................32
  142.          9.2  Differences from OPS5................................32
  143.          9.3  Compiler Switches....................................34
  144.          9.4  Run-Time Switches....................................35
  145.          9.5  Interfacing With External Code.......................35
  146.             9.5.1  Data Types......................................36
  147.             9.5.2  The Result Element..............................37
  148.             9.5.3  Interning and String Spaces.....................37
  149.             9.5.4  Functions Versus Actions........................39
  150.        10. References..............................................40
  151.  
  152.        Appendix A - Dollar Library Description.....................41
  153.        Appendix B - String Library Description.....................44
  154.  
  155.        Index.......................................................45
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.        OPS5c User's Guide
  203.  
  204.  
  205.        1.  Introduction
  206.  
  207.        1.1  What is OPS5c?
  208.  
  209.             OPS5c is a  compiled  version  of  the  OPS5  expert  system
  210.        language originally developed at Carnegie-Mellon University.   It
  211.        belongs to a class of languages which are referred  to  as  rule-
  212.        based (or production-based) expert  systems.   In  such  systems,
  213.        knowledge  is  expressed  as  a  set  of   rules   (also   called
  214.        productions).   These   rules are meant to express some deductive
  215.        statements which may be used as applicable in solving  a  problem
  216.        requiring an expert level of  performance.   If  you  have  never
  217.        programmed in a rule-based language, expect  to  spend  a  little
  218.        time  "getting  up  to  speed".   The   methodologies   used   in
  219.        programming  such  systems  are   considerably   different   from
  220.        programming in conventional programming languages.   This  manual
  221.        should serve as a brief overview of the operation  of  production
  222.        systems (PS's) in general and the OPS5c programming  language  in
  223.        particular.  There are several good texts that you  may  want  to
  224.        consult  in  order  to  get  better  acquainted  with  production
  225.        systems and several are specific to the OPS5 language.
  226.  
  227.  
  228.        1.2  OPS5 History
  229.  
  230.             OPS5  is  part  of  a  family  of  languages  developed   at
  231.        Carnegie-Mellon University  by  Charles  Forgy,  John  McDermott,
  232.        Allen  Newell,  and  Michael  Rychener  in  the  mid-70's.    The
  233.        inference engine used by  OPS5  is  based  on  the  RETE  pattern
  234.        matching algorithm developed  by  Charles  Forgy.   The  original
  235.        systems were written in Lisp.  They read in OPS5 source code  and
  236.        produced  an  intermediate  pseudo-code  which  could   then   be
  237.        interpreted by the OPS5  inference  engine.   Much  of  the  OPS5
  238.        language semantics indicate the underlying Lisp language used  in
  239.        coding the first system.  Another version of OPS5 was written  in
  240.        a language called BLISS.   The  BLISS  system  runs  considerably
  241.        faster  than  the  original  interpreted  Lisp   but   had   some
  242.        limitations  not  present  in  the  Lisp  version.   More  recent
  243.        versions have been written in Common Lisp which  run  many  times
  244.        faster than the original Lisp version, partially  due  to  better
  245.        Lisp coding and probably to some extent due  to  greater  variety
  246.        and power of the  data  structures  and  functions  available  in
  247.        Common Lisp.  The most recent version  of  OPS5  from  CMU  is  a
  248.        system called ParaOps which  compiles  OPS5  source  directly  to
  249.        machine language.  While being considerably faster than  previous
  250.        OPS5 versions the ParaOps system is very machine specific  as  it
  251.        produces assembly language as its output.
  252.             The OPS5c system was designed to accept a language as  close
  253.        to the OPS5 language definition as possible.  As with  the  BLISS
  254.        version of OPS5, some language  features  were  not  implemented.
  255.        OPS5c  is,  however,  approximately  98%  true  to  the  language
  256.        definition and the features missing are not likely to  be  missed
  257.        by most OPS5 programmers.  Unlike previous  systems,  OPS5c  uses
  258.        the  TREAT pattern matching algorithm  developed  by  Dr.  D.  P.
  259.  
  260.  
  261.                                      - 4 -
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.                                                       OPS5c User's Guide
  269.  
  270.  
  271.        Miranker.  In general, the TREAT algorithm has shown  to  be  the
  272.        superior algorithm in most cases.  The OPS5c  compiler  takes  as
  273.        input  an  OPS5  source  program  and  produces  code  in  the  C
  274.        programming language as output.  This code is then  compiled  and
  275.        linked with a run-time library module to  produce  an  executable
  276.        of the OPS5 program.  The main emphasis of this  system,  besides
  277.        OPS5 source code  compatibility,  is  speed.   Whenever  a  speed
  278.        versus space trade-off was encountered during system design,  the
  279.        option  producing  the  fastest  execution  was   almost   always
  280.        selected (within reason of course).  A limited amount of  testing
  281.        on small programs done in December 1988  showed  that  the  OPS5c
  282.        system showed a 30-120% speed  advantage  on  benchmark  programs
  283.        over the then fastest known OPS5 system.   Additional  speed  and
  284.        space  improvements have been  made  to  the  system  since  that
  285.        preliminary testing occurred.  Additional benefits of  OPS5c  are
  286.        that it may be interfaced with other languages  (primarily  C  at
  287.        the moment).  The main disadvantage to OPS5c  is  that  it  often
  288.        produces large executables.  It is not recommended  for  machines
  289.        with less than 1 Meg. of RAM unless only small rule  systems  are
  290.        used.
  291.  
  292.  
  293.        1.3  Production Systems Overview
  294.  
  295.             In   describing   production   systems   in   general,   the
  296.        descriptions will be of systems which have architectures  similar
  297.        to OPS5.  OPS5 terminology will be used as much  as  possible  so
  298.        that  any  reference  to  external   materials   will   be   more
  299.        understandable to the reader.
  300.             As previously mentioned, production  systems  consist  of  a
  301.        set of rules, each of which consists of  two  parts.   These  are
  302.        the antecedent, more commonly known as the left-hand side  (LHS),
  303.        and the consequent, more commonly known as  the  right-hand  side
  304.        (RHS).  The LHS can be thought  of  as  a  series  of  conditions
  305.        which when all are true simultaneously, make  the  rule  eligible
  306.        to "fire".  A rule may fire  when  all  its  LHS  parts,  called  
  307.        condition  elements  (CEs), are true and it has been selected  as
  308.        the correct rule to fire.  In  firing,  the  rule  instructs  the
  309.        system to perform one or more actions as indicated  by  the  RHS.
  310.        The determination of when a rule may fire as well as what  effect
  311.        it's actions have when  it  does  fire  is  dictated  by  working
  312.        memory (WM).
  313.             Working  memory is  best  thought  of  as  a  set  of  facts
  314.        maintained by OPS5.   These  facts  take  the  form  of  discrete
  315.        records  similar  to  structs  in  the  C  language.   Each  such
  316.        structure belongs to a  'class'.  Each class may have attributes,
  317.        which act as data slots, defined for it.  Declarations  of  valid
  318.        classes and their attributes must precede the  rules  definitions
  319.        in the OPS5 source file.  A typical declaration might be:
  320.  
  321.             (literalize person name age height weight)
  322.  
  323.        We  could  then  begin  creating  instances  of  this  class   to
  324.        represent individual  facts.   Even  with  only  one  such  class
  325.  
  326.  
  327.                                      - 5 -
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.        OPS5c User's Guide
  335.  
  336.  
  337.        definition we might want to represent a set of facts such as:
  338.  
  339.             (person ^name John ^age 23 ^height 69 ^weight 165)
  340.             (person ^name Mary ^age 18 ^height 62)
  341.             (person ^name Mark ^age 18)
  342.  
  343.        Each such instance is called a  working memory element (WME).  It
  344.        is these elements which are matched against the patterns  of  the
  345.        LHS of each rule.  When a rule is fired, statements  in  the  RHS
  346.        may add to, remove  from,  or  modify  the  contents  of  working
  347.        memory.
  348.             In general, a production system executes a cycle of  phases.
  349.        The phases of  a  PS  cycle  are  MATCH, CONFLICT RESOLUTION, and 
  350.        ACT.  The MATCH and ACT phases we have mentioned  earlier.   They
  351.        corresponding to matching patterns of the LHS to  working  memory
  352.        elements and performing the actions of the RHS  when  a  rule  is
  353.        selected to fire.  The intermediate phase,  CONFLICT  RESOLUTION,
  354.        determines how a rule is selected amongst many possibilities  for
  355.        firing.  After the system has performed MATCH  against  the  LHSs
  356.        of all rules, there may either be more than one rule which has  a
  357.        LHS match or a rule could have one or more ways  of  producing  a
  358.        match.  The first case should be very obvious.  It  simply  means
  359.        that the facts supporting more than one rule  firing  exist.   It
  360.        is up to CONFLICT RESOLUTION to decide which rule  will  fire  on
  361.        the current cycle.  In the second case, we may  find  that  there
  362.        exists more than one way of matching WMEs to the LHS  of  one  or
  363.        more rules.  As an example, given the three WMEs above,  the  LHS
  364.        of a rule such as
  365.  
  366.             (person ^age > 20)
  367.             (person ^age < 20)
  368.  
  369.        could be matched in two ways.  We  can  form  a  pair  using  the
  370.        first and second WMEs or we can form a pair using the  first  and
  371.        third WMEs.  Each combination of valid mapping  of  WMEs  to  the
  372.        CEs of a rule constitutes what is called an  instance.  OPS5 will
  373.        calculate all the instances it can,  then  select  one  instance,
  374.        and hence the rule  that  it  corresponds  to,  to  fire  on  the
  375.        current cycle.  As we shall later see, instances may be  created,
  376.        but are never guaranteed to be selected to be fired.  Other  more
  377.        appropriate instances may be created during the  MATCH  phase  or
  378.        it is possible for instances to be destroyed.  At any  moment  in
  379.        time, if  we  were  to  stop  the  system  and  examine  all  the
  380.        instances we would  refer  to  this  set  of  instances  as  the  
  381.        conflict  set.   The  CONFLICT  RESOLUTION  phase  examines   the
  382.        conflict set after completing the matching of WMEs added  to  the
  383.        system in the ACT phase of the previous  cycle.   Note  that  the
  384.        MATCH phase performs an  incremental  matching.   It  needs  only
  385.        perform matching  for  newly  added  WMEs  since  the  result  of
  386.        matching produces  instances  and  all  instances  produced  from
  387.        previously added WMEs have already been calculated  and  retained
  388.        in the conflict set.
  389.             The cycle that  we  have  just  described  is  initiated  by
  390.        adding WMEs to working memory, thus causing  matching  with  LHSs
  391.  
  392.  
  393.                                      - 6 -
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.                                                       OPS5c User's Guide
  401.  
  402.  
  403.        of the rules in the system.  The cycle will continue until  there
  404.        are no more instances in the conflict set,  hence  no  rules  can
  405.        fire,  or  a  rule  fires  which  contains   an   explicit   halt
  406.        instruction in its RHS.  Hopefully in either case the system  has
  407.        arrived at a solution to the problem at hand.
  408.             It should  be  noted  that  in  our  brief  description  of  
  409.        CONFLICT  RESOLUTION, we indicated  that  the  system  selects  a
  410.        specific instance to fire.  We speak of instances  firing  rather
  411.        than rules for several reasons.  First, it is important  to  know
  412.        exactly what WMEs match particular CEs.  This is  because  is  it
  413.        common practice for an action in the RHS of a rule  to  reference
  414.        values in the WMEs which match the LHS CEs.  Thus  we  must  know
  415.        exactly which elements match which  CEs  in  order  to  know  the
  416.        appropriate value to use in the actions.   Second,  we  associate
  417.        an instance with a specific  rule,  so  specifying  the  instance
  418.        specifies the rule implicitly.  As we shall  see  later  when  we
  419.        describe how CONFLICT RESOLUTION is performed, the  set  of  WMEs
  420.        that form a particular instance determines  its  "priority"  that
  421.        is calculated by CONFLICT RESOLUTION.  All instances are  ordered
  422.        by priority at the end of the MATCH phase and the  instance  with
  423.        highest priority is selected to fire.
  424.             Additionally,  we  should   address   the   OPS5c   matching
  425.        algorithm at a slightly higher level of  detail.   These  details
  426.        apply specifically  to  the  TREAT match algorithm used by OPS5c.
  427.        The traditional match  algorithm  for  OPS5  is  the  RETE match.
  428.        Refer  to  [Miranker87]  or   other   reference   materials   for
  429.        additional details on the TREAT and RETE algorithms.   Associated
  430.        with each CE is a data structure called  an  alpha memory (amem).
  431.        Such a structure also exists in the RETE algorithm.   As  we  add
  432.        new WMEs to working memory, we must first decide  which  CEs  the
  433.        new WME might be associated  with  in  the  process  of  creating
  434.        instances.  A WME can be associated with some CE for the  purpose
  435.        of creating an instance only if it passes all the  constant tests
  436.        as well as all  variable binding tests.  Constant tests are those
  437.        whose values are not variables but  either  numeric  or  symbolic
  438.        constants.  Variable tests make  comparisons  relative  to  other
  439.        WMEs bound to CEs in the rule.  While the variable binding  tests
  440.        depend on what WMEs are currently bound to the  other  CEs  in  a
  441.        rule, the constant tests are independent of other WMEs.  Thus  it
  442.        makes sense to perform these tests  only  once  for  each  CE/WME
  443.        combination and if the WME passed the constant tests for the  CE,
  444.        we store the WME in the alpha memory of the CE.  In that  fashion
  445.        we some other WME is added to another CE  of  the  rule,  we  can
  446.        scan  the  alpha  memory  structure  of  each  CE  to  look   for
  447.        candidates for satisfying variable bindings  rather  than  having
  448.        to scan all of working memory.  Usually  a  WME  will  match  the
  449.        constant tests of many CEs and therefore will be stored  in  many
  450.        alpha memories.   We  sometimes  refer  to  the  MATCH  phase  as
  451.        containing  two  sub-phases,  SELECT  and  JOIN (these terms come
  452.        from database terminology).  The SELECT sub-phase corresponds  to
  453.        performing constant tests for a newly added  WME  so  it  can  be
  454.        added to the appropriate  alpha  memories.   The  JOIN  sub-phase
  455.        corresponds to the variable binding tests that are  performed  in
  456.        order to try to create instances to  be  added  to  the  conflict
  457.  
  458.  
  459.                                      - 7 -
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.        OPS5c User's Guide
  467.  
  468.  
  469.        set.
  470.             As a recap,  we  may  describe  the  incremental matching as
  471.        such.  When a new WME is matched, we examine all CEs which  refer
  472.        to the same class as the WME being added.  If all constant  tests
  473.        of a particular CE are satisfied by the WME, we add  the  WME  to
  474.        the  alpha  memory of the CE.  At this point we may stop and look
  475.        for  correct  variable  bindings  in  the  rule   that   the   CE
  476.        participates in.  We do this by scanning all the  alpha  memories
  477.        of the other CEs to  find  consistent  variable  bindings.   Note
  478.        that if we find consistent bindings for all CEs of the  rule,  we
  479.        create  an  instance.  Also note that the instance  MUST  contain
  480.        the new WME bound to the CE that we have just added the  WME  to.
  481.        Actually we add to the alpha memory of a  CE,  not  the  CE,  but
  482.        this is mearly terminology and  we  often  use  the  terms  alpha
  483.        memory, amem, and CE to mean the same thing -  namely  a  storage
  484.        structure for WMEs which satisfy the constant tests of the CE.
  485.  
  486.  
  487.  
  488.  
  489.  
  490.  
  491.  
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.                                      - 8 -
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.                                                       OPS5c User's Guide
  533.  
  534.  
  535.        2.  Working Memory
  536.  
  537.        2.1  Class Declarations
  538.  
  539.             As mentioned earlier, classes  and  the  attributes they use
  540.        are usually declared before being  used  in  any  rules.   It  is
  541.        usually best to declare all classes and  specify  all  attributes
  542.        to be used with each class although neither  of  these  practices
  543.        are enforced by OPS5.  OPS5 will  allow  the  user  to  reference
  544.        class names that have not  been  defined.   It  will  also  allow
  545.        attributes which were defined in one class to  be  referenced  in
  546.        another class.  This is due to the simplistic symbol  table  kept
  547.        by OPS5 systems.  No record is kept of which classes  declared  a
  548.        particular attribute name.  Unfortunately this "feature"  is  one
  549.        that has been exploited by OPS5 programmers in the past and  thus
  550.        is handled similarly by OPS5c to maintain compatibility.
  551.             Classes  and  their  attributes  are  declared  using  the   
  552.        LITERALIZE  statement.   As  seen  in  an  earlier  example,  the
  553.        keyword LITERALIZE is followed by  a  class  name  which  may  be
  554.        followed by zero or more attribute names.   The  entire  declara-
  555.        tion must be enclosed in parentheses.  It is  acceptable  to  use
  556.        the same attribute name in different classes  but  a  class  name
  557.        may appear in only one LITERALIZE statement.
  558.  
  559.  
  560.        2.2  Working Memory Element Structure
  561.  
  562.             A  working  memory  element (WME) consists of a time tag and
  563.        an  array  of  attributes.  The  time  tag  is  a  unique  number
  564.        assigned to each WME at the  time  of  its  creation.   The  more
  565.        recent the WME the larger its time tag will be.  The  time tag is
  566.        used not only as  a  unique  identifier,  but  is  also  the  key
  567.        feature in the algorithms used by CONFLICT RESOLUTION.   In  most
  568.        OPS5 implementations there are 127 attribute "slots"  defined  in
  569.        each WME.  Regardless of the number of attributes defined  for  a
  570.        class, each WME contains room for  127  attribute  values.   When
  571.        the declarations section of an OPS5 program has  been  parsed  by
  572.        an OPS5 interpreter or compiler, it assigns  an  offset  in  this
  573.        array to each of the attribute names  that  have  been  declared.
  574.        The offset  assigned  to  a  particular  attribute  is  the  same
  575.        regardless of the class  (or  classes)  the  attribute  has  been
  576.        declared in.  The  algorithm  must  consider  which  classes  the
  577.        attribute has been declared in so that it  can  assign  a  single
  578.        offset to an attribute name while not assigning the  same  offset
  579.        to attributes which appear in the same class.   Because  of  this
  580.        it is not valid to assume that  the  order  of  attributes  in  a
  581.        class declaration has anything to  do  with  the  assignment  of  
  582.        offsets to those attributes.  Assignments may be in  a  different
  583.        order and may not be sequential. While  most  classes  will  have
  584.        offsets not used by any attributes declared in  that  class,  the
  585.        unused offsets may have assigned offsets that are  either  higher
  586.        numbered or lower numbered.   If  a  programmer  chooses  to  use
  587.        attribute names in classes for which they were not declared  when
  588.        writing rules, there is the risk that the offset assigned to  two
  589.  
  590.  
  591.                                      - 9 -
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.        OPS5c User's Guide
  599.  
  600.  
  601.        or more attributes used in the  same  class  will  be  the  same.
  602.        This will  usually  cause  over-writing  of  data  and  incorrect
  603.        program behavior.  This is the main reason  that  declaration  of
  604.        all attributes to be used in a class is a recommended practice.
  605.             OPS5 also has a mechanism for  allowing  the  programmer  to
  606.        control the offset assignments to certain  attributes.   This  is
  607.        accomplished with  the  LITERAL statement.  This statement simply
  608.        assigns  offsets  to  attributes  blindly.   An  example  LITERAL
  609.        declaration follows.
  610.  
  611.             (literal name = 2 age = 4 address = 45)
  612.  
  613.        Attribute names appearing in a LITERAL statement do not  have  to
  614.        appear in any LITERALIZE, though they may.  Since LITERAL  state-
  615.        ments are processed before LITERALIZEs (although they may  appear
  616.        intermixed in the source code),  the  system  may  find  that  it
  617.        cannot  provide  assignments  for  LITERALIZEs  which  allow   no
  618.        duplicate offsets in a class,  in  which  case  the  system  will
  619.        abort with an error message.
  620.             Attributes in a WME are similar  to  Lisp  atoms.  For those
  621.        not familiar with Lisp, an atom  is  a  structure  with  a  field
  622.        indicating the atom type (symbol, integer, float, etc.)  and  the
  623.        data value.  Because the type is associated with the data  value,
  624.        not with the attribute name or location, we may  assign  a  value
  625.        with one data type (say  an  integer)  to  some  attribute,  then
  626.        reassign  another  value  with  a  different  data  type  (say  a
  627.        string).  Certain functions in the OPS5 language,  namely  calcu-
  628.        lations and relational comparison  predicates, are the only parts
  629.        of the language that operate on specific types.  Attribute  types
  630.        will also be a concern to the programmer who wishes to  interface
  631.        OPS5c programs to external C code.  It should be noted  that  for
  632.        comparison  purposes  symbols (strings) must be identical and are 
  633.        case sensitive, i.e. 'dog' is not equal to 'DOG'.  Normally  OPS5
  634.        will consider an integer and floating point value to be equal  if
  635.        their difference, when the integer  is  converted  to  float,  is
  636.        zero.  In OPS5c numeric attributes must be the same  type  to  be
  637.        equal regardless of their values.  By defining  the  preprocessor
  638.        symbol  COERCE  while  compiling  the  C  output  of  the   OPS5c
  639.        compiler, the system will  perform  coercion of incompatible data
  640.        types whenever possible.
  641.             Whenever  a  WME  is  created  and  assigned   values,   the
  642.        attribute positions which are not assigned values explicitly  are
  643.        given  a  value  of  "nil" (a symbolic atom).  Rules may test for
  644.        unassigned attribute values by comparing to  "nil"  in  a  CE  in
  645.        their LHS.
  646.  
  647.  
  648.        2.3  Vector Attributes
  649.  
  650.             Normally we associate a single value  with  each  attribute.
  651.        There are cases where we wish to store a set of values  that  are
  652.        associated with a single attribute name.  OPS5  provides  methods
  653.        for finding the offset of an attribute and referencing  attribute
  654.        slots a certain relative distance past the offset.  Thus  we  can
  655.  
  656.  
  657.                                     - 10 -
  658.  
  659.  
  660.  
  661.  
  662.  
  663.  
  664.                                                       OPS5c User's Guide
  665.  
  666.  
  667.        say that the set of values associated with some attribute is  all
  668.        values with an offset equal to or greater  than  the  attribute's
  669.        offset.  In order to may sure  that  we  don't  over-write  other
  670.        attribute  slots,  we  may  ensure  that  there  are   no   other
  671.        attributes (at least in a specific  class)  that  has  a  greater
  672.        offset.  This is done by declaring the  "multi-valued"  attribute
  673.        in the class (or  classes)  it  will  be  used  and  additionally
  674.        declaring it as a vector attribute.  One or more  attributes  may
  675.        be declared as  vector  attributes  using  one  or  more  VECTOR-
  676.        ATTRIBUTE statements.  An example would be:
  677.  
  678.             (vector-attribute classmates teachers)
  679.  
  680.        It should be noted that only one vector attribute is allowed  per
  681.        class and any attributes declared to be  vector  attributes  will
  682.        be treated as vector attributes in  all  classes  that  they  are
  683.        declared in.
  684.             The user should  be  aware  that  the  OPS5c  implementation
  685.        normally will not treat  all  WMEs  as  being  of  equal  length.
  686.        Instead it sizes each class according to the  maximum  offset  of
  687.        the attributes declared in that class.  If the class  declaration
  688.        contains an attribute that has  been  declared  to  be  a  vector
  689.        attribute, then the class will be sized with the  maximum  number
  690.        of  attributes  that   a   WME   can   contain   (128   in   this
  691.        implementation).  There are ways, however, of  forcing  all  WMEs
  692.        or WMEs of certain classes to be of specific  lengths.   See  the
  693.        discussion of the '-w' compiler or run-time switch.  This  action
  694.        might  be  desirable  (in  fact  necessary  for  correct  program
  695.        execution) if the program being run references  attributes  in  a
  696.        class for which the attribute was not declared.  This  is  a  bad
  697.        programming practice but the above mentioned  override  mechanism
  698.        can compensate.
  699.  
  700.  
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.  
  715.  
  716.  
  717.  
  718.  
  719.  
  720.  
  721.  
  722.  
  723.                                     - 11 -
  724.  
  725.  
  726.  
  727.  
  728.  
  729.  
  730.        OPS5c User's Guide
  731.  
  732.  
  733.        3.  Rules
  734.  
  735.  
  736.        3.1  Rule Structure
  737.  
  738.             Below is a template for the syntactic structure of  an  OPS5
  739.        rule:
  740.  
  741.             (p rule-name
  742.                  (class-a ^attr-1 value-1 ^attr-2 value-2 ...)
  743.                  (class-b ^attr-x value-x ^attr-y value-y ...)
  744.                  ...
  745.             -->
  746.                  (action-a parameters-for-a)
  747.                  (action-b parameters-for-b)
  748.                  ...
  749.             )
  750.  
  751.        The  indentation  is  optional  but  is  used  to  emphasize  the
  752.        different parts of a rule.  A more  terse  template  for  a  rule
  753.        might be:
  754.  
  755.             (p rule-name LHS-CEs --> RHS-actions)
  756.  
  757.        Rule names may be any string which does not contain any blanks.
  758.  
  759.  
  760.  
  761.  
  762.  
  763.  
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770.  
  771.  
  772.  
  773.  
  774.  
  775.  
  776.  
  777.  
  778.  
  779.  
  780.  
  781.  
  782.  
  783.  
  784.  
  785.  
  786.  
  787.  
  788.  
  789.                                     - 12 -
  790.  
  791.  
  792.  
  793.  
  794.  
  795.  
  796.                                                       OPS5c User's Guide
  797.  
  798.  
  799.        4.  The LHS
  800.  
  801.  
  802.        4.1  Condition Elements
  803.  
  804.             As previously mentioned, the LHS of a rule  is  composed  of
  805.        one  or  more  condition  elements (CEs).  A  CE  is  a  set  of  
  806.        attribute-value  pairs.   This  is  usually  an  attribute   name
  807.        followed immediately by a value.  In OPS5 an attribute name in  a
  808.        CE  is  distinguished  from  a  value  by  prefacing   a   string
  809.        (representing a declared attribute  name)  with  a  caret  ('^').
  810.        Spaces between the caret and the attribute name are allowed.   If
  811.        a value is not immediately preceded by an  attribute  name,  then
  812.        the value pertains to the attribute  slot  immediately  following
  813.        the previously  referenced  attribute  slot.   If  there  are  no
  814.        previously referenced attributes then the value pertains  to  the
  815.        first WME attribute, which is always the class name of  the  WME.
  816.        Another alternate method of specifying an attribute  position  is
  817.        to follow the caret with a  numeric  value.   The  numeric  value
  818.        indicates an attribute offset for the WME.
  819.  
  820.  
  821.        4.2  Variables
  822.  
  823.             Instead of specifying an attribute value after an  attribute
  824.        name,  an  attribute  variable may be  specified.   An  attribute
  825.        value is indicated by enclosing  a  string  in  angled  brackets.
  826.        The string  may  not  contain  any  blanks.   An  example  of  an
  827.        attribute variable is <age>.  The first appearance of a  variable
  828.        tells the system to create a variable binding  by  assigning  the
  829.        attribute value of whatever WME is bound to that  CE  during  the
  830.        matching  process  to   the   indicated   variable.    Subsequent
  831.        occurrences of the variable  in  the  rule  will  substitute  the
  832.        variable  value  literally  for  the  variable  occurrence.   The
  833.        variable may appear in subsequent CEs or in actions in the  right
  834.        hand side.
  835.  
  836.  
  837.        4.3  Quoting
  838.  
  839.             Quoting symbols is a method of  using  characters  that  are
  840.        not normally allowed in symbols or have  some  other  meaning  to
  841.        the system.  For example, normally a  string  with  one  or  more
  842.        imbedded spaces would be interpreted by the  system  as  multiple
  843.        symbols rather than a single symbol.  Perhaps we wish to  include
  844.        the  caret  character  as  the  first  character  of  a   symbol.
  845.        Normally the system would interpret any symbol  starting  with  a
  846.        caret to be an attribute name rather than a value.
  847.             One method of quoting which is supported both in  rules  and
  848.        in the entering of commands from the top level  (see  section  8)
  849.        is the use of quote characters  to  surround  the  string  to  be
  850.        treated  as  a  single  symbol.   The  three   quote   characters
  851.        supported are  the  single  quote,  the  double  quote,  and  the
  852.        vertical bar.  Another method of quoting which is only  supported
  853.  
  854.  
  855.                                     - 13 -
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862.        OPS5c User's Guide
  863.  
  864.  
  865.        in CEs  is  by  using  the  OPS5  quote  operator  which  is  two
  866.        consecutive slashes.  Using this method, a  space  must  separate
  867.        the quote operator and the symbol to be  quoted.   Some  examples
  868.        of quoted symbols are:
  869.             "Hello world!"
  870.             '"hi," she said'
  871.             |That's correct|
  872.             // ^dog
  873.  
  874.  
  875.        4.4  Predicates
  876.  
  877.             Predicates are relational  tests  that  the  user  may  want
  878.        performed between the attributes  of  WMEs  and  the  CE  pattern
  879.        during  matching.   Predicates  are  specified  by  placing   the
  880.        predicate preceding the  test  value  where  one  would  normally
  881.        specify a value to match against.  For example,  if  we  want  to
  882.        test for children under the  age  of  twelve,  we  might  specify
  883.        '^age < 12'  as  our  attribute-value  pair.   We  may  also  use
  884.        variables instead of constants to  test  the  attribute  against,
  885.        thus we could have written '^age < <my-age>'.   Seven  predicates
  886.        are defined, equal '=', not equal '<>', less  than  '<',  greater
  887.        than '>', less than or equal '<=', greater than  or  equal  '>=',
  888.        and same '<=>'.  The same predicate test to see if the  attribute
  889.        and test value have the same type, i.e. if both  are  numeric  or
  890.        both are symbolic.  If the variable has  been  previously  bound,
  891.        i.e. it either appears in some earlier CE or appears  earlier  in
  892.        the current CE, then in the absence of a  predicate,  equivalence
  893.        testing is  performed  with  the  variable  binding  rather  than
  894.        creating a new variable binding.
  895.  
  896.  
  897.        4.5  Conjuctions
  898.  
  899.             We use braces ('{','}') when we wish to indicate that  there
  900.        are several tests that we wish a single attribute value  to  hold
  901.        true for.  For example if we are looking  for  an  age  group  we
  902.        might specify '^age {> 20 < 25}'.  If we also wish  to  bind  the
  903.        attribute value to an unbound variable, we  should  include  that
  904.        variable without specifying a test predicate.   Additionally,  of
  905.        course, the variable should not have appeared in  a  previous  CE
  906.        of that rule (i.e. the variable is unbound).  For example:  '^age
  907.        {<her-age> > 20 < 25}'.
  908.             Another use for braces is as a place holder  in  a  pattern.
  909.        The pattern (cat {} black) will match WMEs of class  'cat'  whose
  910.        second attribute may be anything and  whose  third  attribute  is
  911.        'black'.  Note that when we say second or third attribute we  are
  912.        referring to the offset numbers  assigned  to  attributes.   This
  913.        may  or  may  not  have  anything  to  do  with  the  order  that
  914.        attributes appear in the literalize statements.
  915.  
  916.  
  917.  
  918.  
  919.  
  920.  
  921.                                     - 14 -
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.                                                       OPS5c User's Guide
  929.  
  930.  
  931.        4.6  Disjunctions
  932.  
  933.             Disjunctions allow the matching of one  of  a  selection  of
  934.        choices.  Disjunctions  are  indicated  by  enclosing  a  set  of
  935.        choices in double angled brackets ('<<','>>').  An example  would
  936.        be the CE
  937.             (cat << black tan yellow >>)
  938.        which would match all WMEs of class 'cat' whose second  attribute
  939.        is either 'black' or 'tan' or 'yellow'.  It should be noted  that
  940.        there  is  an  implicit  quoting  mechanism   in   the   use   of
  941.        disjunctions.  A CE such as
  942.             (cat << black tan <x> >>)
  943.        would specify the literal '<x>' as an  alternate  value  for  the
  944.        second attribute rather than match the  current  binding  of  the
  945.        variable x.  Hence, variables are not  allowed  to  be  bound  or
  946.        tested in a disjunction.
  947.  
  948.  
  949.        4.7  Negated Condition Elements
  950.  
  951.             Condition elements may be negated by placing  a  minus  sign
  952.        before the rest of the CE.  This has the meaning  that  in  order
  953.        for a rule to fire, we must be able to find a  WME  that  matches
  954.        each of the positive CEs and there must not exist any  WMEs  that
  955.        match the negated CEs.  As with positive  CEs,  negated  CEs  may
  956.        contain tests against previously bound variables.  In  order  for
  957.        an instance to be created,  there  must  exist  a  WME  for  each
  958.        positive CE which satisfies all tests whether they are  constants
  959.        tests or variable bindings that  test  values  between  different
  960.        CEs.  When negated  CEs  are  present  in  a  rule  we  have  the
  961.        additional restriction that  for  any  potential  instance  which
  962.        might be created when we consider  only  positive  CEs,  we  must
  963.        also not be able to find any WMEs matching the negated CEs.   Any
  964.        WMEs which match a negated CE  (for  a  particular  instance)  is
  965.        said to "block" the creation  of  that  instance  for  the  rule.
  966.        Since negated CEs may contain variable bindings,  we  must  speak
  967.        of WMEs that match negated CEs  with  respect  to  the  instance.
  968.        The  instance  (considering  positive  CEs  only)   defines   the
  969.        variable bindings which can decide which WMEs do or  don't  match
  970.        negated CEs.  This also implies that variables  cannot  be  bound
  971.        in negated CEs which might  be  intuitively  expected  since  the
  972.        meaning of a  negated  CE  is  that  something  of  this  pattern
  973.        couldn't be found.
  974.             If all  WMEs  which  block  an  instance  are  removed  from
  975.        working memory, and those WMEs which match the positive  elements
  976.        remain, then one or more instances will be formed once  the  last
  977.        blocking WME has been deleted.   (Remember  that  this  does  not
  978.        mean that the instances from this rule will necessarily fire,  it
  979.        just means that its instances are added to the conflict  set  and
  980.        are allowed to compete in the selection of the next  instance  to
  981.        fire.)  Similarly, if a WME is added to  working  memory  and  it
  982.        matches a negated CE  for  some  instance  which  was  previously
  983.        added to the conflict set but not yet fired, that  instance  will
  984.        be removed from the conflict set.  Should the blocking WME  later
  985.  
  986.  
  987.                                     - 15 -
  988.  
  989.  
  990.  
  991.  
  992.  
  993.  
  994.        OPS5c User's Guide
  995.  
  996.  
  997.        be removed and all the WMEs matching  positive  CEs  remain,  the
  998.        instance will be recreated and added to the conflict  set.   This
  999.        is the only set of circumstances which allows a  unique  instance
  1000.        to be created more than once (i.e. it  must  be  blocked  between
  1001.        creations).  This may also occur even if the  instance  had  been
  1002.        fired.   The  removal  of  the  blocking  WME  might  still  have
  1003.        resulted in a second (or subsequent) recreation of the  instance.
  1004.        This is usually not a concern but in some  cases  the  programmer
  1005.        should take into account that such a situation can occur.
  1006.             For convenience, we will use the abbreviations +CE  and  -CE
  1007.        to stand for positive condition element  and  negative  condition
  1008.        element, respectively.
  1009.  
  1010.  
  1011.        4.8  Element Variables
  1012.  
  1013.             Just as we might wish  to  bind  an  attribute  value  to  a
  1014.        variable for use in RHS actions, we  may  also  wish  to  specify
  1015.        that some action be taken with respect  to  the  WME  matching  a
  1016.        particular CE of the rule.  We may designate such a  WME  in  one
  1017.        of two ways.  The first is simply a reference number,  between  1
  1018.        and the maximum number  of  CEs  per  rule  (64  in  the  current
  1019.        implementation), which specifies the CEs appearence  position  in
  1020.        the LHS.  Another method is by associating a  name  with  certain
  1021.        CEs that we may wish to reference.  Such a  name  is  called  an  
  1022.        element  variable.  This is the preferred method  of  referencing
  1023.        WMEs from the RHS since deletion and addition of new CEs  in  the
  1024.        rule can cause position shifts which would affect  the  numerical
  1025.        element designator, but not an element variable.  We  specify  an
  1026.        element variable by placing a variable name  (a  symbol  enclosed
  1027.        in angled brackets) either before the CE  or  after  the  CE  and
  1028.        enclosing  both  the  variable  and  CE  in  braces.   Below  are
  1029.        examples of element variables in the LHS.
  1030.  
  1031.             { <THE-CAR> (car ^manufacturer buick ^make <m-name>) }
  1032.             { (person ^hobby tennis) <THE-PLAYER> }
  1033.  
  1034.        We shall see how to use such references  when  we  discuss  those
  1035.        RHS actions that operate on WME references.
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050.  
  1051.  
  1052.  
  1053.                                     - 16 -
  1054.  
  1055.  
  1056.  
  1057.  
  1058.  
  1059.  
  1060.                                                       OPS5c User's Guide
  1061.  
  1062.  
  1063.        5.  The RHS
  1064.  
  1065.  
  1066.        5.1  Element Designators
  1067.  
  1068.             Some RHS actions require an  element designator to specify a
  1069.        particular WME of the instance being fired that the action is  to
  1070.        be  performed  on.   There  are   two   ways   of   making   this
  1071.        specification - an element variable, or a  numeric  offset.   The
  1072.        element variable specification is  simply  the  element  variable
  1073.        name  (with  enclosing  angled  brackets).   The  numeric  offset
  1074.        specification indicates the number of the WME  appearing  in  the
  1075.        instance.  Note that these numbers start at one and  -CEs are not
  1076.        counted.  Thus if a LHS has a +CE followed by a -CE  followed  by
  1077.        another +CE, the numeric  element  designator  for  the  last  CE
  1078.        would be two.
  1079.  
  1080.  
  1081.        5.2  RHS Patterns
  1082.  
  1083.             Patterns in the RHS are similar in form to those of the  LHS
  1084.        but have a somewhat different meaning.  RHS patterns  consist  of
  1085.        constants,  variables,  attribute  names,  the   quote   operator
  1086.        ('//'), and function  calls.   Unlike  LHS  patterns,  which  are
  1087.        evaluated at compile time, the evaluation of RHS patterns  occurs
  1088.        at run time.  The evaluation of RHS patterns has  the  effect  of
  1089.        altering a global buffer  area  called  the  result element.  The 
  1090.        result  element  (RE) is simply an array of attributes.  One  can
  1091.        think of it as a  global  WME  which  is  not  actually  part  of
  1092.        working memory.  Associated with the RE is a pointer which  keeps
  1093.        track of the current position in the buffer.  Terms  in  the  RHS
  1094.        pattern  which  evaluate  to  attribute  references  (names   and
  1095.        attribute offsets) have the effect  of  moving  the  RE  pointer,
  1096.        while terms which evaluate to values are placed in the  locations
  1097.        indicated by the RE pointer.  When multiple values are placed  in
  1098.        the  RE  without  an  intervening  attribute   name   or   offset
  1099.        reference,  the  values  are  placed  in  consecutive   locations
  1100.        starting at the location indicated by the RE pointer.  Each  time
  1101.        a different pattern is evaluated, the result  element  is  filled
  1102.        with  the  atom  special  'nil' prior to evaluation.  As we shall
  1103.        see later, the RE is used not only for  pattern  evaluation,  but
  1104.        for argument passing and  value  reception  with  external  user-
  1105.        defined functions and actions.
  1106.             All RHS actions consist of an action keyword, followed by  a
  1107.        pattern.  The pattern is evaluated  and  the  resulting  list  of
  1108.        instantiated  values  is  used  as  arguments  for  the   action.
  1109.        Pattern instantiation is quite similar to that in  the  LHS  with
  1110.        the  effects  of  constants,  attribute  names,  and  the   quote
  1111.        operator being identical.  With the exception  of  the  BIND  and
  1112.        CBIND actions, variables in RHS patterns are not bound,  but  are
  1113.        mearly instantiated.  Functions do not  exist  in  LHS  patterns.
  1114.        In RHS patterns they are indicated by enclosing a list of one  or
  1115.        more terms  in  parentheses.   The  term  following  the  opening
  1116.        parenthesis must be a constant specifying the  function  name  to
  1117.  
  1118.  
  1119.                                     - 17 -
  1120.  
  1121.  
  1122.  
  1123.  
  1124.  
  1125.  
  1126.        OPS5c User's Guide
  1127.  
  1128.  
  1129.        be called.  The remainder of the list is evaluated and passed  to
  1130.        the function  as  arguments.   Function  arguments  may  only  be
  1131.        constants or variables, thus no nesting of function calls may  be
  1132.        used.  Refer to  section  5.3  for  a  discussion  of  predefined
  1133.        functions and to section 9.5 for  a  discussion  of  user-defined
  1134.        functions.
  1135.             Another difference between LHS patterns and RHS patterns  is
  1136.        the  use  of  variable  attribute  names.   The  term  '^<aname>'
  1137.        appearing in the RHS would be interpreted as the  attribute  name
  1138.        or offset number specified in the variable 'aname'.  This  syntax
  1139.        is not allowed in LHS patterns.
  1140.  
  1141.  
  1142.        5.3  Pre-defined Functions
  1143.  
  1144.             All RHS functions return one or more values  at  consecutive
  1145.        locations in the result element.  The values  returned  start  at
  1146.        the current position in the result element.
  1147.  
  1148.        5.3.1  genatom
  1149.  
  1150.             The genatom function is used to generate a  unique  symbolic
  1151.        value.  This value is placed  at  the  current  position  in  the
  1152.        result element.
  1153.  
  1154.  
  1155.        5.3.2  litval
  1156.  
  1157.             This function  takes  a  single  symbol  or  variable  which
  1158.        represents an attribute name.  It returns the offset assigned  to
  1159.        it in all WMEs.  If the  symbol  or  variable  value  is  not  an
  1160.        attribute name, then the function returns zero.
  1161.  
  1162.  
  1163.        5.3.3  substr
  1164.  
  1165.             This function extracts a sequence  of  one  or  more  values
  1166.        from a WME and places them in  sequential  locations  in  the  RE
  1167.        starting at the current position.   The  first  argument  to  the
  1168.        function is the element designator which  indicates  the  WME  to
  1169.        extract from.  The second and third arguments indicate  attribute
  1170.        offsets which specify the range of attribute values  to  copy  to
  1171.        the  RE.  Either of these two arguments may be  specified  as  an
  1172.        integer, an attribute name (which is converted  to  its  assigned
  1173.        offset), or a variable that is bound to an integer  or  attribute
  1174.        name.  The order of the range specification  arguments  does  not
  1175.        matter.
  1176.  
  1177.  
  1178.        5.3.4  compute
  1179.  
  1180.             This function  evaluates  arithmetic  expressions.   Expres-
  1181.        sions may contain the operators '+',  '-',  '*',  '//', and '\\'.
  1182.        The latter two are used for division and modulus.   Operands  may
  1183.  
  1184.  
  1185.                                     - 18 -
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191.  
  1192.                                                       OPS5c User's Guide
  1193.  
  1194.  
  1195.        be numeric constants or variables bound to numeric values.   Note
  1196.        that  compute  has  no  operator  precedence  and  operators  are
  1197.        evaluated from right to left (not left  to  right  as  one  might
  1198.        expect).  This may be overriden by the use of parentheses.
  1199.  
  1200.  
  1201.        5.3.5  accept
  1202.  
  1203.             This function reads input from some input stream.  An  input
  1204.        stream is usually keyboard input typed by the user,  or  a  file.
  1205.        If called without arguments, accept reads input from the  current
  1206.        default  input  stream.   A  single  optional  argument  may   be
  1207.        supplied which indicates an alternate input stream to read  from.
  1208.        The optional argument must be  either  a  symbol  or  a  variable
  1209.        bound to a  symbolic  value.   This  string  indicates  the  file
  1210.        handle of the input stream (see section 5.4 for  descriptions  of
  1211.        accessing file streams using RHS actions or top level commands).
  1212.             If the input begins with an open parenthesis,  then  a  list
  1213.        of values will be read and placed at sequential locations in  the
  1214.        RE starting at the current  position.   Input  is  read  until  a
  1215.        closing parenthesis is found.  If  the  first  character  of  the
  1216.        input is not an open parenthesis, then a single  input  value  is
  1217.        read into the RE.
  1218.             If the input function tries to read past the end of a  file,
  1219.        then the atom 'end-of-file' is the value returned.
  1220.  
  1221.  
  1222.        5.3.6  acceptline
  1223.  
  1224.             This function also reads input from a  stream,  but  differs
  1225.        from the accept function in that it reads  exactly  one  line  of
  1226.        input, strips out all parentheses, and  then  places  the  values
  1227.        read into the RE.  Parameters are optional.   If  any  parameters
  1228.        are supplied, they are used to specify the  input  stream  and/or
  1229.        affect the behavior of the function when there are no  values  in
  1230.        the line input or an end of file condition exists.  If the  first
  1231.        parameter evaluates to a symbol associated with an input  stream,
  1232.        then that parameter acts as a specification of the  input  stream
  1233.        to read from.  If the first parameter is not associated  with  an
  1234.        input  stream,  then  it  is  treated  the  same  as   subsequent
  1235.        parameters.   The  remaining  parameters,  if  present,  will  be
  1236.        placed in the RE if an empty input line is read.
  1237.  
  1238.  
  1239.        5.4  RHS Actions
  1240.  
  1241.             The actions supported in  the  RHS  for  OPS5c  are  'make',
  1242.        'remove', 'modify', 'write',  'bind',  'cbind',  'call',  'halt',
  1243.        'openfile', 'closefile',  and  'default'.   These  are  the  same
  1244.        actions supported by  OPS5  except  that  OPS5  also  supports  a
  1245.        'build' command that may be used to dynamically add rules to  the
  1246.        system at run-time.  This is not supported in the OPS5c  compiled
  1247.        environment.
  1248.  
  1249.  
  1250.  
  1251.                                     - 19 -
  1252.  
  1253.  
  1254.  
  1255.  
  1256.  
  1257.  
  1258.        OPS5c User's Guide
  1259.  
  1260.  
  1261.  
  1262.        5.4.1  make
  1263.  
  1264.             The make command is used to create new WMEs to be  added  to
  1265.        WM during the  MATCH  phase  of  the  next  cycle.   The  pattern
  1266.        following the make keyword is  instantiated  and  a  new  WME  is
  1267.        created.  Minimally a class  name  must  be  given  and  optional
  1268.        attribute-value pairs or simply  values  may  be  supplied.   For
  1269.        example, the action:
  1270.  
  1271.             (make person ^name Cindy ^age 25)
  1272.  
  1273.        creates a new WME for the class person with the value 'Cindy'  in
  1274.        the attribute slot for 'name' and the value 25 in  the  attribute
  1275.        slot for age.   Similarly  to  patterns  appearing  in  the  LHS,
  1276.        attribute names  may  be  omitted  and  values  are  assigned  to
  1277.        sequential slot offsets after the last referenced offset.
  1278.  
  1279.  
  1280.        5.4.2  remove
  1281.  
  1282.             The remove action indicates one  or  more  WME  elements  to
  1283.        remove.   These  WMEs  are  indicates  by  a  list   of   element
  1284.        designators, which as previously mentioned can consist of  either
  1285.        a numeric CE offset (starting at 1) or an element  variable  name
  1286.        (including the angled brackets surrounding  the  variable  name).
  1287.        It is not an error to remove the  same  CE  twice,  but  removals
  1288.        after the first are ignored.
  1289.  
  1290.  
  1291.        5.4.3  modify
  1292.  
  1293.             The modify action can be thought of as a make followed by  a
  1294.        remove.  The first parameter to modify must be a  single  element
  1295.        designator.  This copies the WME specified to  a  temporary  work
  1296.        buffer where the remaining pattern elements  are  interpreted  as
  1297.        attribute-value pairs that alter the buffer  before  executing  a
  1298.        make command using the  buffer  values.   Once  a  WME  has  been
  1299.        modified, the old WME is removed.   Since  multiple  removes  are
  1300.        allowed without ill side effects, and removes  are  not  actually
  1301.        processed until  the  RHS  actions  have  been  executed,  it  is
  1302.        possible to have multiple modifications of a  single  WME  create
  1303.        several new WMEs.  For example, a rule such as:
  1304.  
  1305.             (p split-path
  1306.                  { <SEGMENT> (segment ^start <s> ^end <e>) }
  1307.                  (new-point ^value <p>)
  1308.             -->
  1309.                  (modify <SEGMENT> ^end <p>)
  1310.                  (modify <SEGMENT> ^start <p>)
  1311.             )
  1312.  
  1313.        could be used to make two line segments from one by adding a  new
  1314.        point in between the lines current start and end points.   Either
  1315.  
  1316.  
  1317.                                     - 20 -
  1318.  
  1319.  
  1320.  
  1321.  
  1322.  
  1323.  
  1324.                                                       OPS5c User's Guide
  1325.  
  1326.  
  1327.        modify command will operate using the original  contents  of  the
  1328.        WME bound to <SEGMENT> and the <SEGMENT> WME will be  removed  at
  1329.        the end of the ACT phase.
  1330.  
  1331.  
  1332.        5.4.4  write
  1333.  
  1334.             The write function  evaluates  a  pattern  and  writes  this
  1335.        output to an output stream.  If the first argument to write is  a
  1336.        symbol (or variable with a symbolic  value)  that  is  associated
  1337.        with an output file handle, then the first argument  acts  as  an
  1338.        output stream specifier, otherwise the first argument is  treated
  1339.        the same as the rest of the arguments.  Each  evaluated  argument
  1340.        is written  to  the  output  stream.   There  are  three  special
  1341.        "functions" which can modify the  action  of  write.   These  are
  1342.        'tabto',  'rjust',  and  'crlf'.  The  tabto  function  takes one
  1343.        argument  which  must  evaluate  to  a  numeric  quantity.   This
  1344.        quantity is the column number that the output cursor is  advanced
  1345.        to by printing space characters.  If the current output  line  is
  1346.        already  past  the  column  number  specified,  then  a   newline
  1347.        character is sent first.  The rjust function also takes a  single
  1348.        numeric parameter.  This indicates  a  field  width.   The  value
  1349.        following the rjust function will be  printed,  right  justified,
  1350.        in a field whose width is x characters, where x is the  value  of
  1351.        the numeric parameter.  The crlf  function  takes  no  arguments.
  1352.        It sends a newline character to the output stream.   These  three
  1353.        special functions are not really functions  at  all.   They  only
  1354.        have meaning with  the  write  action  and  are  referred  to  as
  1355.        functions because they follow function call syntax.  Example:
  1356.  
  1357.             (write (crlf) "The age of" <name> "is" <age> (crlf))
  1358.  
  1359.        It should be noted that printing of subsequent values always  has
  1360.        a space between the values.  Thus (write "hello" !) will  produce
  1361.        the output 'hello !', not 'hello!'.
  1362.  
  1363.  
  1364.        5.4.5  bind
  1365.  
  1366.             The bind action is used to bind a functions return value  to
  1367.        a variable.  Example:
  1368.             (bind <x> (compute <x> * 2))
  1369.  
  1370.  
  1371.        5.4.6  cbind
  1372.  
  1373.             The cbind action is used to bind an element variable to  the
  1374.        last element that was added to working memory.  The  addition  is
  1375.        usually due to a previous make or modify action, though WMEs  may
  1376.        be added by calling external functions.  The cbind  action  takes
  1377.        a single argument, the variable to be bound to.
  1378.  
  1379.  
  1380.  
  1381.  
  1382.  
  1383.                                     - 21 -
  1384.  
  1385.  
  1386.  
  1387.  
  1388.  
  1389.  
  1390.        OPS5c User's Guide
  1391.  
  1392.  
  1393.        5.4.7  call
  1394.  
  1395.             The call action is used to  invole  a  user-defined  action.
  1396.        The first parameter to call is the  name  of  the  user  routine.
  1397.        The  remaining  parameters  are  pattern   elements   which   are
  1398.        evaluated before being  passed  as  parameters  to  the  routine.
  1399.        Section 9.5 and the Appendicies describe interfacing  with  user-
  1400.        written C routines and library routines that may be  called  from
  1401.        these  routines.   Names  of  user-defined  routines  should   be
  1402.        declared  (with  class  declarations)  by  using   the   external
  1403.        declaration.  Example:
  1404.             /* In declaration section */
  1405.             (external DrawLine)
  1406.             ...
  1407.             /* Some rule RHS */
  1408.             (call DrawLine <x> <y>)
  1409.  
  1410.  
  1411.        5.4.8  halt
  1412.  
  1413.             The halt action terminates  program  execution  irregardless
  1414.        of the state of working memory or the conflict set.
  1415.  
  1416.  
  1417.        5.4.9  openfile
  1418.  
  1419.             The openfile action opens a file for reading or writing  and
  1420.        assigns a file handle to a symbol for future  reference  to  that
  1421.        file.  The first parameter supplied to openfile is  the  name  to
  1422.        be used as a file handle in subsequent  references.   The  second
  1423.        parameter is the file name,  usually  in  quotation  marks.   The
  1424.        third and final parameter is one of two keywords, either 'in'  or
  1425.        'out'.  These indicate if the file is being  opened  in  read  or
  1426.        write mode, respectively.
  1427.  
  1428.  
  1429.        5.4.10  closefile
  1430.  
  1431.             The closefile action  is  used  to  close  files  previously
  1432.        opened with the openfile action.  It takes the file's  handle  as
  1433.        a single argument.
  1434.  
  1435.        5.4.11  default
  1436.  
  1437.             The default action determines where various  output  streams
  1438.        created by OPS5c are directed or where the input stream  is  read
  1439.        from.  The three streams used by OPS5c are 'trace', 'write',  and
  1440.        'accept'.  The  trace stream is where any trace information, such
  1441.        as which rule fired on each cycle, is directed.   Various  levels
  1442.        of trace information, including  no  trace  information,  can  be
  1443.        provided as the system executes.  See the description of the  top
  1444.        level 'watch' command in  section  8  for  information  on  trace
  1445.        levels.   The  write stream is where output from the write action
  1446.        is  directed.   The   accept stream is the input stream where the
  1447.  
  1448.  
  1449.                                     - 22 -
  1450.  
  1451.  
  1452.  
  1453.  
  1454.  
  1455.  
  1456.                                                       OPS5c User's Guide
  1457.  
  1458.  
  1459.        accept and acceptline functions read  input  from.   One  of  the
  1460.        more common uses of default is to redirect trace  information  to
  1461.        a file.
  1462.             The default action takes two parameters, a file  handle  and
  1463.        a stream designator which must be one  of  'trace',  'write',  or
  1464.        'accept'.  Example:
  1465.  
  1466.             (openfile trace-output "foobar.trace" out)
  1467.             (default trace-output trace)
  1468.             /* run program */
  1469.             (closefile trace-output)
  1470.  
  1471.  
  1472.  
  1473.  
  1474.  
  1475.  
  1476.  
  1477.  
  1478.  
  1479.  
  1480.  
  1481.  
  1482.  
  1483.  
  1484.  
  1485.  
  1486.  
  1487.  
  1488.  
  1489.  
  1490.  
  1491.  
  1492.  
  1493.  
  1494.  
  1495.  
  1496.  
  1497.  
  1498.  
  1499.  
  1500.  
  1501.  
  1502.  
  1503.  
  1504.  
  1505.  
  1506.  
  1507.  
  1508.  
  1509.  
  1510.  
  1511.  
  1512.  
  1513.  
  1514.  
  1515.                                     - 23 -
  1516.  
  1517.  
  1518.  
  1519.  
  1520.  
  1521.  
  1522.        OPS5c User's Guide
  1523.  
  1524.  
  1525.        6.  Conflict Resolution
  1526.  
  1527.             The  purpose  of   conflict  resolution  is  to  choose  one
  1528.        instantiation from the conflict set  which  is  to  fire  on  the
  1529.        current  cycle.   There  are  many  criterion  which  may   drive
  1530.        conflict resolution in a system like  OPS5,  but  the  two  major
  1531.        driving  forces  in  OPS5  conflict  resolution  strategies  are  
  1532.        recency  and  specificity.  These are discussed  in  more  detail
  1533.        below.
  1534.             The conflict set  may  be  viewed  as  a  list  of  possible
  1535.        assertions that may be made on  a  particular  cycle.   A  single
  1536.        instance  can  be  thought  of  as  a  set  of  facts   and   the
  1537.        justification (rule) which allows new facts to be  asserted  (the
  1538.        RHS actions).  Once a  particular  instance has been selected for
  1539.        firing by conflict resolution, we must remove that instance  from
  1540.        the  conflict  set, otherwise it  may  fire  again  and  cause  a
  1541.        condition known as trivial cycling  where  the  same  rule  fires
  1542.        repeatedly.
  1543.             When a new assertion has been made, say adding a new WME  to
  1544.        the working memory, it is  frequently  the  case  that  this  new
  1545.        element will be the basis for further inferences.   Most  systems
  1546.        will have a large search  space  of  possible  solutions  to  the
  1547.        problem being solved and the most common system  behavior  is  to
  1548.        find one of many possible solutions rather  than  all  solutions.
  1549.        this implies that in scanning parts of  the  solution  space,  we
  1550.        wish to traverse the tree of selection possibilities in a  depth-
  1551.        first fashion as opposed to a  breadth-first  fashion.   This  is
  1552.        done by assuming that given two facts  to  reason  on,  the  most
  1553.        recent fact is probably the better one  to  base  assertions  on.
  1554.        This heuristic is known as recency and is a strong driving  force
  1555.        in the OPS5 conflict resolution strategies.  To support  recency,
  1556.        each WME in the system is assigned a time tag.  This is a  unique
  1557.        integer number given to the element at the time of its  creation.
  1558.        Part of the conflict resolution strategy is to look at  the  time
  1559.        tags of all the WMEs that make up each instance,  and  order  the
  1560.        instances  according  to  the  recency  of  the  WME   time  tags
  1561.        associated with it.
  1562.             Another heuristic used in conflict  resolution  is  that  of
  1563.        specificity.  Specificity assumes that  if  two  rules  are  very
  1564.        similar, but one either contains more condition elements  in  the
  1565.        LHS or more tests for the same number of  condition  elements  in
  1566.        the LHS, then the rule with more  CEs/tests  must  be  a  special
  1567.        case of the other, more general, rule.  Specificity demands  that
  1568.        we execute the rule with more CEs/tests first.
  1569.             There are two conflict resolution strategies  in  OPS5,  LEX
  1570.        and MEA.  They are fairly simple,  with  MEA being a modification
  1571.        of LEX.  We shall describe the  LEX strategy first.  The criteria
  1572.        for comparing two instances is used to order  the  conflict  set.
  1573.        First,  the  time  tags  of  the  positive  CEs  are  ordered  in
  1574.        descending  order.   The  first  time  tag  in  each  series   is
  1575.        compared.  The instance with the greater tag is the  more  recent
  1576.        and is thus preferred over the other one.  If the time  tags  are
  1577.        the same, then the second tags in each list are  compared.   This
  1578.        continues until a difference in  the  lists  is  noted.   If  the
  1579.  
  1580.  
  1581.                                     - 24 -
  1582.  
  1583.  
  1584.  
  1585.  
  1586.  
  1587.  
  1588.                                                       OPS5c User's Guide
  1589.  
  1590.  
  1591.        lists are of unequal length, then the longer list  is  preferred,
  1592.        provided the pair-wise comparisons  of  tags  do  not  favor  the
  1593.        shorter list before its elements are  exhausted.   This  provides
  1594.        for selection of the more specific rule (the one  with  more  CEs
  1595.        has the longer list).  If two lists are the same length and  have
  1596.        the same elements, then the number of tests (both constant  tests
  1597.        and variable binding tests) are compared and the rule  containing
  1598.        the most tests is selected.  This also favors the  more  specific
  1599.        rule.  If the  number  of  tests  are  equal  then  an  arbitrary
  1600.        selection if made.
  1601.             The  MEA strategy has the same rules  as  the  LEX  strategy
  1602.        with one change.  We first compare the time tags associated  with
  1603.        the first CE of each instance's  rule.   If  that  comparison  is
  1604.        equivalent, then  we  order  the  remaining time tags and perform
  1605.        the pair-wise comparisons.  This modification exists because  the
  1606.        first CE of a rule  is  often  a  context clause which can define
  1607.        when a rule is  eligible  to  fire.   More  will  be  said  about
  1608.        context clauses in section 7.
  1609.  
  1610.  
  1611.  
  1612.  
  1613.  
  1614.  
  1615.  
  1616.  
  1617.  
  1618.  
  1619.  
  1620.  
  1621.  
  1622.  
  1623.  
  1624.  
  1625.  
  1626.  
  1627.  
  1628.  
  1629.  
  1630.  
  1631.  
  1632.  
  1633.  
  1634.  
  1635.  
  1636.  
  1637.  
  1638.  
  1639.  
  1640.  
  1641.  
  1642.  
  1643.  
  1644.  
  1645.  
  1646.  
  1647.                                     - 25 -
  1648.  
  1649.  
  1650.  
  1651.  
  1652.  
  1653.  
  1654.        OPS5c User's Guide
  1655.  
  1656.  
  1657.        7.  OPS5 Programming
  1658.  
  1659.             This section is not intended to teach you all the tricks  of
  1660.        programming in OPS5.  There are books devoted  to  this  subject.
  1661.        Instead, this section is intended to give you an overview of  the
  1662.        type of  structures  you  can  expect  to  see  in  typical  OPS5
  1663.        programs and some of the issues that should be  of  concern  when
  1664.        you begin writing your own OPS5 programs.  The novice  programmer
  1665.        will find this  section  important  to  understanding  rule-based
  1666.        programming in OPS5 while those who have some knowledge  of  OPS5
  1667.        will probably already know most of the points outlined here.
  1668.             By its  nature,  rule  based  programming  is  data  driven.
  1669.        Input data in the form of assertions active certain rules,  which
  1670.        may make new assertions activating different rules and so on.   A
  1671.        program execution is a constant  cycle  of  modifying  facts  and
  1672.        making and retracting assertions via rule firing.  This is  quite
  1673.        a bit different from the declarative programming  languages  that
  1674.        most  of  use  use  such  as  C,  Fortran,   Pascal,   etc.    In
  1675.        conventional languages we specify an algorithm or a  sequence  of
  1676.        steps to perform.  We know that A will be done before  B  because
  1677.        we have written the program such that the function that  performs
  1678.        A will be  called  before  the  function  that  performs  B.   In
  1679.        contrast, in a rule based system we  make  statements  that  when
  1680.        certain facts hold true, it is appropriate  to  assert  that  the
  1681.        addition or deletion of facts in  the  database  are  appropriate
  1682.        should a given rule be selected to fire.  Usually we  don't  know
  1683.        when a rule will fire, the number of times  it  should  fire,  or
  1684.        even if it will fire.  If our logic  manipulating  the  facts  is
  1685.        correct then we shouldn't care.
  1686.             While  this  seems  like  a  desirable  trait,   there   are
  1687.        pitfalls.  First, the methods that we use to solve a problem  can
  1688.        almost never be totally data driven.  Each method we use  can  be
  1689.        broken up into parts or sections  which  solve  subtasks  of  the
  1690.        larger problem.  Many times it is necessary to solve one  subtask
  1691.        before  considering  the  solutions  to  other  subtasks.  For an
  1692.        efficiency  standpoint  it  is  not  reasonable  to   incur   the
  1693.        execution overhead involved in maintaining a state  of  reasoning
  1694.        for some rule if we know  that  rule  does  not  pertain  to  the
  1695.        current subtask the system is trying to solve.  Not  only  is  it
  1696.        inefficient to perform such unnecessary calculation,  it  may  be
  1697.        incorrect to do so.  If we have no mechanism to disallow  a  rule
  1698.        from firing, it may  activate  and  fire  prematurely  making  an
  1699.        incorrect assertion based on incomplete data.   To  prevent  both
  1700.        undesirable actions, we  have  certain  implementation  dependent
  1701.        rule evaluation procedures and also allow the programmer  to  use
  1702.        such features to  control  the  flow  of  the  program  execution
  1703.        somewhat.
  1704.             We wish  the  system  to  do  the  minimum  amount  of  work
  1705.        necessary to correctly match rules that may fire with facts.   It
  1706.        should be obvious that if we do not have at  least  one  fact  in
  1707.        each alpha memory for the +CEs in a rule, then we  cannot  create
  1708.        an instantiation for that rule.  If the rule  does  not  have  at
  1709.        least one WME in each of its +CEs, then the  rule  is  considered
  1710.        inactive and the only computation  done  is  to  place  new  WMEs
  1711.  
  1712.  
  1713.                                     - 26 -
  1714.  
  1715.  
  1716.  
  1717.  
  1718.  
  1719.  
  1720.                                                       OPS5c User's Guide
  1721.  
  1722.  
  1723.        being added to working memory into the appropriate CEs  for  that
  1724.        rule.  We do not attempt to calculate variable  bindings  because
  1725.        we know that at least one CE cannot have anything  bound  to  it,
  1726.        thus  such  calculations   would   be   useless.    This   simple
  1727.        implementation rule allows a programmer to greatly increase  both
  1728.        program efficiency as well as control.  This is  accomplished  by
  1729.        the  programmer's  use  of  context clauses.  Normally, a context
  1730.        clause is a class declared by the programmer which describes  the
  1731.        current goal or focus of the program.  Normally such a  class  is
  1732.        given a name like 'goal' or 'context'.  Each rule in  the  system
  1733.        (or at least most of them) will contain  one  CE  specifying  the
  1734.        context in which that rule is eligible to fire.  If  the  context
  1735.        is  currently  set  to  something  else,  and  we  have   already
  1736.        specified that there is only one context element  in  the  system
  1737.        at a time, then the first CE of that rule will  have  nothing  in
  1738.        it and we will not attempt variable binding computations for  the
  1739.        rule when WMEs are added to the  other  CEs  of  the  rule.   The
  1740.        context specifies that the current  goal,  and  nothing  but  the
  1741.        current goal, will  be  worked  on  by  the  system.   Rules  not
  1742.        pertaining to solving  the  current  goal  are  given  a  minimal
  1743.        amount of attention by the system.  Note that when  we  recognize
  1744.        that it is appropriate to change the system goal, we must  modify
  1745.        the existing goal element.  Frequently, this will cause  a  large
  1746.        amount or work to be  done,  because  we  will  destroy  all  the
  1747.        instance that the old goal element participated in and there  are
  1748.        often many rules that the creation of a  new  goal  element  will
  1749.        activate and perform  variable  binding  calculations  for.   For
  1750.        this reason, we can see that it  would  be  very  inefficient  to
  1751.        code  a  rule  based  program  with  a  large  number  of   rules
  1752.        pertaining  to  a  few  goals  and  switch  between   the   goals
  1753.        frequently.  Each goal switch could force a large amount of  work
  1754.        to be done.
  1755.             One trick that is common in  OPS5  programming  pertains  to
  1756.        switching  contexts or goals.  Often we  may  desire  to  execute
  1757.        some task (a specific goal or context) until  no  more  rules  in
  1758.        that context can fire.  Then we wish to change the goal.   To  do
  1759.        this we rely on the OPS5 conflict resolution strategy.   Remember
  1760.        that in resolving which  instance  is  to  fire  on  the  current
  1761.        cycle, we use time ordered tag lists.  If  we  exhaust  one  list
  1762.        while doing the comparison between two  lists,  then  the  longer
  1763.        list wins.  This is  the  same  as  saying  that  when  comparing
  1764.        instances  between  two  rules,   given   identical   time   tags
  1765.        participating in both rules, the rule with the most CEs will  win
  1766.        the conflict resolution.  We can therefore write rules to  switch
  1767.        context by relying on the fact that such a rule will  never  fire
  1768.        as long as a more specific rule (one with more CEs) can fire.
  1769.             As an example, suppose that some part of our  algorithm  has
  1770.        produced a set of guesses, we select one  guess  to  take  action
  1771.        on, then we wish to  delete  the  non-selected  guesses,  perhaps
  1772.        with the intent of creating a new set later.  We might see  rules
  1773.        such as:
  1774.  
  1775.  
  1776.  
  1777.  
  1778.  
  1779.                                     - 27 -
  1780.  
  1781.  
  1782.  
  1783.  
  1784.  
  1785.  
  1786.        OPS5c User's Guide
  1787.  
  1788.  
  1789.  
  1790.             (p remove-guesses
  1791.                  (goal ^value delete-guesses)
  1792.                  { <THE-GUESS> (guess) }
  1793.             -->
  1794.                  (remove <THE-GUESS>)
  1795.             )
  1796.  
  1797.             (p process-guess-start
  1798.                  { <THE-GOAL> (goal ^value delete-guesses) }
  1799.             -->
  1800.                  (modify <THE-GOAL> ^value process-guess)
  1801.             )
  1802.  
  1803.        We know that although the second  rule  will  be  active  through
  1804.        this subtask, it cannot fire unless  the  is  no  possibility  of
  1805.        firing the first  rule.   Hence  we  will  achieve  our  goal  of
  1806.        deleting the old  guesses  before  moving  on  the  the  task  of
  1807.        processing the one selected.
  1808.  
  1809.  
  1810.  
  1811.  
  1812.  
  1813.  
  1814.  
  1815.  
  1816.  
  1817.  
  1818.  
  1819.  
  1820.  
  1821.  
  1822.  
  1823.  
  1824.  
  1825.  
  1826.  
  1827.  
  1828.  
  1829.  
  1830.  
  1831.  
  1832.  
  1833.  
  1834.  
  1835.  
  1836.  
  1837.  
  1838.  
  1839.  
  1840.  
  1841.  
  1842.  
  1843.  
  1844.  
  1845.                                     - 28 -
  1846.  
  1847.  
  1848.  
  1849.  
  1850.  
  1851.  
  1852.                                                       OPS5c User's Guide
  1853.  
  1854.  
  1855.        8.  Top Level Commands
  1856.  
  1857.             Top  level commands are the interpreted  commands  that  the
  1858.        user types in.  The top level commands used  in  OPS5c  are  very
  1859.        similar to those used in the lisp-based OPS5.  Some commands  are
  1860.        unsupported while other commands are added to  OPS5c  to  enhance
  1861.        its usability.
  1862.             When a user executes  an  OPS5c  program,  a  few  lines  of
  1863.        system identification are printed followed  by  the  prompt  'Top
  1864.        Level> '.  At this point the user can type any  of  the  commands
  1865.        listed in this section.  Minimally, the user  must  do  something
  1866.        to initiate processing by the OPS5c system.  Initially  there  is
  1867.        no information in the  working  memory.   In  general  there  are
  1868.        three ways that a user can initiate program  execution  once  the
  1869.        initial top level prompt is given.  He  can  created  WMEs  using
  1870.        the  top  level  make command.  He may use the  make  command  to
  1871.        create a start symbol.  Or he may use the  include command to add
  1872.        many WMEs to working memory.
  1873.             The first two methods are the same techniques used in  OPS5.
  1874.        If the user knows that certain WMEs need to  be  created  at  the
  1875.        start of every run, he can create an  initialization  rule  whose
  1876.        RHS makes the  necessary  elements.   The  LHS  of  such  a  rule
  1877.        usually depends on the existance of  a  single  element  of  some
  1878.        class such as 'start'.   The  last  method  allows  the  user  to
  1879.        specify a path name to a file containing make  statements.   This
  1880.        file will be interpreted to create the WMEs  needed.   Note  that
  1881.        unlike OPS5, the act of making a WME mearly means  that  we  have
  1882.        created storage representing the WME  and  correctly  initialized
  1883.        the WME's  attribute  values.   The  WME  will  not  actually  be
  1884.        inserted into working memory until a cycle is run.  Thus  if  you
  1885.        type make commands from the top level prompt, do  not  expect  to
  1886.        see any instances  created  or  insertions  into  alpha  memories
  1887.        until you have issued  the  run command.  The same effect will be
  1888.        noticed  when  using  the  remove command.  Instances that may be
  1889.        created as a result of removing a WME will not be observed  until
  1890.        one or more cycles of  the  system  are  executed  following  the
  1891.        issuing of the remove command.
  1892.             Many RHS actions are also supported as  top  level  commands
  1893.        with nearly identical syntax.  The main  limitations  imposed  by
  1894.        using the top level command  is  that  you  cannot  use  variable
  1895.        references, the quote  operator  ('//'), and cannot use functions
  1896.        as arguments.  Commands with these characteristics include  make, 
  1897.        remove,  openfile,  closefile, default, and call.  For the remove
  1898.        command, instead of supplying a list of  element  designators  to
  1899.        delete, the user supplies a list  of  time  tag  elements  to  be
  1900.        deleted.  If called with an asterisk as the  only  argument,  the
  1901.        command will delete all of working memory.   The  following  sub-
  1902.        sections  describe  the  remaining  top  level  commands.   Those
  1903.        specific to OPS5c are indicated as such.
  1904.  
  1905.  
  1906.        8.1  include (OPS5c only)
  1907.  
  1908.             This command is used to read a  text  file  containing  make
  1909.  
  1910.  
  1911.                                     - 29 -
  1912.  
  1913.  
  1914.  
  1915.  
  1916.  
  1917.  
  1918.        OPS5c User's Guide
  1919.  
  1920.  
  1921.        commands.  Appropriate WMEs are created  but  are  not  added  to
  1922.        working memory until at least one cycle has been  run  after  the
  1923.        include command.  The include command takes a file  name  as  the
  1924.        single parameter.  The file  name  may  be  quoted  using  double
  1925.        quotes, single quotes, or vertical bars. Example:
  1926.             (include "auto-diagnose.input")
  1927.  
  1928.  
  1929.        8.2  run
  1930.  
  1931.             This command starts executing the match/resolve/act  cycles.
  1932.        Optionally an integer parameter may be given to run  to  indicate
  1933.        the maximum number of cycles to run before returning to  the  top
  1934.        level.  This is particularly useful for debugging where  you  may
  1935.        want to examine the state of the system after  a  certain  number
  1936.        of cycles and before the program has completed executing.
  1937.  
  1938.  
  1939.        8.3  watch
  1940.  
  1941.             This command tells the system how much trace information  to
  1942.        print out as the system executes.  Watch takes a  single  numeric
  1943.        parameter which must be 0, 1, 2, or 3.  A  watch  level  of  zero
  1944.        indicates that no trace information is to be  output.   The  only
  1945.        output  from  the  program  will  be  that  generated  by   write
  1946.        statements in the RHS of  rules  that  fire  or  from  externally
  1947.        called procedures.  The default watch level of one will  print  a
  1948.        cycle number, rule number, rule name and time tag list  for  each
  1949.        instance that is fired.  A watch level  two  provides  the  watch
  1950.        level one information in  addition  to  indicating  when  working
  1951.        memory elements are made or removed.  The WME itself  is  printed
  1952.        preceded by '>>' if the element is being added to working  memory
  1953.        or '<<' if the element is being removed from working  memory.   A
  1954.        watch level of three will indicate watch  level  two  information
  1955.        in addition to showing instances being  added  and  removed  from
  1956.        the conflict set.
  1957.  
  1958.  
  1959.        8.4  ppwm
  1960.  
  1961.             The ppwm command is used to  print  WMEs.   The  command  is
  1962.        followed by a pattern which can only  consist  of  constants  and
  1963.        attribute names.  The system will scan all of working memory  for
  1964.        the specified pattern and will print out each WME (including  its
  1965.        assigned time tag) that matches the pattern.  When  no  arguments
  1966.        are given to ppwm, all of working memory is printed.
  1967.  
  1968.  
  1969.        8.5  wm
  1970.  
  1971.             The wm command is similar to the ppwm  command  except  that
  1972.        instead of specifying a pattern as the arguments of the  command,
  1973.        a  list  of  time tags is specified.  Similar to ppwm the command
  1974.        prints all of working memory if it is called with no arguments.
  1975.  
  1976.  
  1977.                                     - 30 -
  1978.  
  1979.  
  1980.  
  1981.  
  1982.  
  1983.  
  1984.                                                       OPS5c User's Guide
  1985.  
  1986.  
  1987.  
  1988.        8.6  cs
  1989.  
  1990.             This command prints out the contents  of  the  conflict set.
  1991.        The  dominant  instance (the instance to fire next) is  indicated
  1992.        as such.
  1993.  
  1994.  
  1995.        8.7  strategy
  1996.  
  1997.             This command selects the conflict resolution  strategy.   It
  1998.        takes either 'lex' or 'mea' as a single argument,  or  if  called
  1999.        with no arguments  it  prints  the  current  conflict  resolution
  2000.        strategy.
  2001.  
  2002.  
  2003.        8.8  pbreak
  2004.  
  2005.             This command can set break points on specific  rules.   When
  2006.        called with a rule name it will set a break point  on  that  rule
  2007.        if one is currently unset or remove a break point for  that  rule
  2008.        if one is  currently  set.   Having  a  break  point  set  for  a
  2009.        particular rule means that the system  will  return  to  the  top
  2010.        level  immediately  after  firing  an  instance  of  that   rule.
  2011.        Issuing the command with no arguments prints  the  names  of  all
  2012.        rules which currently have break points set.
  2013.  
  2014.  
  2015.        8.9  dump (OPS5c only)
  2016.  
  2017.             This command prints out the  contents  (WME  time  tags)  of
  2018.        each of the alpha memories.
  2019.  
  2020.  
  2021.        8.10  size (OPS5c only)
  2022.  
  2023.             This command prints out the number of WMEs  in  the  working
  2024.        memory.  The number of WMEs in each class is listed separately.
  2025.  
  2026.  
  2027.  
  2028.  
  2029.  
  2030.  
  2031.  
  2032.  
  2033.  
  2034.  
  2035.  
  2036.  
  2037.  
  2038.  
  2039.  
  2040.  
  2041.  
  2042.  
  2043.                                     - 31 -
  2044.  
  2045.  
  2046.  
  2047.  
  2048.  
  2049.  
  2050.        OPS5c User's Guide
  2051.  
  2052.  
  2053.        9.  The OPS5c System
  2054.  
  2055.  
  2056.        9.1  Installing OPS5c
  2057.  
  2058.             Each  C  compiler  has  directories  that  it  searches  for
  2059.        standard include files  when  compiling  and  standard  libraries
  2060.        when linking.  By placing the appropriate OPS5c  files  in  these
  2061.        places, you may use the OPS5c compiler just as you would  your  C
  2062.        compiler.  The compiler itself is called 'ops5c'.  You may  place
  2063.        this somewhere in your  execution  path  if  you  desire  (C:  or
  2064.        elsewhere).  The header file needed to compile  the  output  from
  2065.        the  OPS5c  compiler  is  called  'o5c.h'.  Place this file  with
  2066.        other standard headers such as  'stdio.h'.   The  OPS5c  run-time
  2067.        library  is  called  'ops5c.lib'.  Place this with your  standard
  2068.        libraries such  as  'c.lib'.   The  commands  for  compiling  the
  2069.        sample program 'tourney.ops' using the Aztec C compiler is  given
  2070.        below:
  2071.  
  2072.             ops5c test_files/tourney.ops
  2073.             cc tourney1.c
  2074.             ln -o tourney tourney1.o -lops5c -lm -lc
  2075.  
  2076.        Note that to produce the very fastest executables  you  may  turn
  2077.        on optimization when compiling the C output file,  but  you  will
  2078.        probably find that this has little effect other than making  your
  2079.        compile take longer.  It is far more important  to  optimize  the
  2080.        library code.  The code provided in the distribution was  created
  2081.        using Aztec C 5.0 with complete optimization turned on (-so).
  2082.  
  2083.  
  2084.        9.2  Differences from OPS5
  2085.  
  2086.  
  2087.             OPS5c was designed to be  as  compatible  as  possible  with
  2088.        existing OPS5  programs.   Complete  compatibility  is  virtually
  2089.        unobtainable since  OPS5c  is  compiled  and  typically  OPS5  is
  2090.        interpreted.   Other  differences  may   be   observed   due   to
  2091.        implementation  details  of  underspecified   features   of   the
  2092.        language.  The following list is a summary of the most  important
  2093.        differences that you may encounter when running OPS5c.
  2094.  
  2095.             o  The pm, matches, excise, and back top level  commands  of
  2096.                OPS5 are not implemented in OPS5c.
  2097.  
  2098.             o  The top level command dump is used to examine  the  alpha
  2099.                memory contents.  It takes no arguments  and  prints  out
  2100.                the contents of all alpha memories.
  2101.  
  2102.             o  The top level command size is used to  count  the  number
  2103.                of elements in each class and add them to  determine  the
  2104.                entire size of working memory.
  2105.  
  2106.             o  The top level include  command  works  similarly  to  the
  2107.  
  2108.  
  2109.                                     - 32 -
  2110.  
  2111.  
  2112.  
  2113.  
  2114.  
  2115.  
  2116.                                                       OPS5c User's Guide
  2117.  
  2118.  
  2119.                load command found in some Lisp implementations of  OPS5.
  2120.                It accepts a file name as  a  parameter.   The  indicated
  2121.                file must contain only make  statements  which  will  add
  2122.                new elements to working memory.
  2123.  
  2124.             o  Several of the '$' functions used by  OPS5  do  not  make
  2125.                sense in a non-Lisp  environment.   Additions  have  also
  2126.                been  made  to  the  $functions  (see  Interfacing   With
  2127.                External Code).
  2128.  
  2129.             o  It may or may not be possible  to  provide  execution  of
  2130.                OPS5c which is identical to that  of  OPS5  for  programs
  2131.                that rely on  arbitrary  selection  of  instances.   This
  2132.                occurs  when  two  are  more  instances  are   considered
  2133.                equivalent by the  conflict  resolution  rules  and  they
  2134.                exist simultaneously in the conflict set.   See  Run-Time
  2135.                Switches for a possible fix to this problem.
  2136.  
  2137.             o  OPS5c does not normally perform coercion between  numeric
  2138.                data types.  You can make the system perform coercion  by
  2139.                defining the preprocessor symbol  COERCE  when  compiling
  2140.                the <program>1.c file.  This will substitute  a  function
  2141.                call to  perform  type  checking  and  coercion  for  the
  2142.                equals and not-equals tests rather than  use  the  macros
  2143.                that are normally used.
  2144.  
  2145.             o  OPS5 specifies that all  WMEs  should  contain  the  same
  2146.                number   of   attributes,    usually    128    in    most
  2147.                implementations.  In order to  conserve  space  on  small
  2148.                systems, OPS5c sizes  all  WMEs  of  a  particular  class
  2149.                according  to  the  maximum  offset  of  the   attributes
  2150.                declared in the class.  (Note that this is not  the  same
  2151.                as the number  of  attributes  in  the  class  since  one
  2152.                attribute may have a large offset assigned to it.)   This
  2153.                may be overriden with the -w switch  at  either  compile-
  2154.                time or run-time.
  2155.  
  2156.             o  OPS5c  supports  modular compilation.  A large system may
  2157.                be compiled into  multiple  C  source  code  files,  then
  2158.                linked together to form an executable.   This  is  useful
  2159.                for systems with small amounts of RAM or  compilers  that
  2160.                cannot handle large symbol tables.  It often  speeds  the
  2161.                compilation process as well.
  2162.  
  2163.             o  It should  be  noted  that  in  this  implementation  the
  2164.                maximum number of CEs per rule is  64.   It  is  STRONGLY
  2165.                recommended that you limit the number of  CEs  per  rule.
  2166.                (No  more  that  10  CEs  per  rule  is   suggested   for
  2167.                performance reasons.)  Large rules should  be  broken  up
  2168.                into smaller ones as necessary.
  2169.  
  2170.  
  2171.  
  2172.  
  2173.  
  2174.  
  2175.                                     - 33 -
  2176.  
  2177.  
  2178.  
  2179.  
  2180.  
  2181.  
  2182.        OPS5c User's Guide
  2183.  
  2184.  
  2185.        9.3  Compiler Switches
  2186.  
  2187.             There are five switches  accepted  by  the  OPS5c  compiler.
  2188.        These are -t, -s, -c, -o and -w.  The most commonly  used  switch
  2189.        is -s.  This switch controls the  ordering  method  used  by  the
  2190.        compiler.   A  separate  join code sequence is generated for each
  2191.        CE of each rule.  There are two methods  used  for  ordering  the
  2192.        scan order of  the  join.   Seed ordering uses the CE being added
  2193.        to as the first CE in the join ordering with  the  remaining  CEs
  2194.        being examined in lexical order.   Heuristic ordering is based on
  2195.        seed ordering but tries to examine CE dependencies to  produce  a
  2196.        more efficient join order of the non-seed  CEs  (those  remaining
  2197.        after  the  seed  CE  has  been  selected).   Normally  heuristic
  2198.        ordering is used since it normally produces results  as  good  or
  2199.        better than seed ordering.  The -s  switch  indicates  that  seed
  2200.        ordering should be  used.   One  item  of  concern  is  that  the
  2201.        heuristic ordering algorithm will perform  exhaustive  search  of
  2202.        all orderings in the worst case.  This  only  happens  for  rules
  2203.        with  highly  connected  CEs  (CEs  which  have  common  variable
  2204.        bindings).  If worst case behavior is  observed,  the  number  of
  2205.        orderings examined is proportional to the square  of  the  number
  2206.        of CEs in a rule, therefore the compilation time for  rules  with
  2207.        a large number of connected CEs may be very high.   The  compiler
  2208.        prints an asterisk to the screen upon  completion  of  each  rule
  2209.        compiled.  If compilation appears to be very slow then  the  user
  2210.        should consider aborting the compile and recompiling with the  -s
  2211.        switch.
  2212.             The  -c  and  -o  switches  are  used  in  conjunction  with
  2213.        creating  multiple  output  modules.  Multiple output modules may
  2214.        be necessary on some systems  to  overcome  certain  software  or
  2215.        hardware  limitations.   When  multiple  output  modules   become
  2216.        necessary,  the  compiler  produces  a  series  of  files   named
  2217.        '<file>#.c', where the # sign is a numeric sequence  number.   It
  2218.        also produces a script  file  called  'comp.sh' which can be used
  2219.        to compile and link the multiple modules.  Multiple  modules  may
  2220.        be advantageous for systems with limited memory which may not  be
  2221.        able to compile an entire large rule system.  They  may  also  be
  2222.        necessary for linkers which have hard set limits  on  the  number
  2223.        of symbols  a  single  object  module  may  have.   Normally  the
  2224.        compiler  counts  functions  produced  for  join  operations  and
  2225.        functions produced for executing right-hand-side actions.   These
  2226.        functions will constitute  symbols  present  in  object  modules.
  2227.        The compiler has  a  cut-off  setting   which  indicates  when  a
  2228.        module has too many symbols.  If compiling an addition rule  into
  2229.        the current module will  exceed  the  symbol  cut-off,  then  the
  2230.        current module is terminated and a new module  is  started.   The
  2231.        default symbol-cutoff value is 3000.  The user may specify a  new
  2232.        cut-off value by using the -c switch with  a  numeric  value  for
  2233.        the symbol cut-off immediately  following.   To  suppress  module
  2234.        creation and produce only one module, use the -o switch.
  2235.             The -t  switch  is  used  to  specify  tracefile  execution.
  2236.        Tracefile execution is used to  run  benchmarks  comparing  OPS5c
  2237.        with other systems.  A tracefile of some  expert  system  run  is
  2238.        produced with the other system using  a  watch  level  2  setting
  2239.  
  2240.  
  2241.                                     - 34 -
  2242.  
  2243.  
  2244.  
  2245.  
  2246.  
  2247.  
  2248.                                                       OPS5c User's Guide
  2249.  
  2250.  
  2251.        (with the watch command).  This tracefile can be  read  by  OPS5c
  2252.        to  determine  appropriate  RHS  actions  after   each   conflict
  2253.        resolution step.  In this way we  do  not  have  to  worry  about
  2254.        recoding external functions used in RHS actions in order  to  run
  2255.        OPS5c, the tracefile will determine RHS actions.  Note that  this
  2256.        method may give poor results since the cost of  interpreting  the
  2257.        tracefile may be considerably  more  or  considerably  less  than
  2258.        that observed had external function  calls  to  C  routines  been
  2259.        used.  To use tracefile execution, follow the -t switch with  the
  2260.        path name of the tracefile.
  2261.             The -w switch allows the user to specify  the  size  of  the
  2262.        WMEs created at run-time.  It applies to all WMEs rather than  to
  2263.        specific classes.   Its  use  is  primarily  for  programs  using
  2264.        undeclared classes or attribute specifications  in  classes  that
  2265.        the attributes were not declared in.  The switch is  followed  by
  2266.        an integer number from 1 to 128 which  indicates  the  number  of
  2267.        attribute slots the WMEs will contain.  This number  must  be  as
  2268.        large as the largest offset of any class or the program will  not
  2269.        execute correctly.  Programs  whose  class  declarations  contain
  2270.        all attributes used by references of that class do  not  have  to
  2271.        worry about setting the -w flag  as  the  system  will  correctly
  2272.        size each class.
  2273.  
  2274.  
  2275.        9.4  Run-Time Switches
  2276.  
  2277.             The executable produced by compiling and linking  the  OPS5c
  2278.        output files will accept three switches  at  run-time,  -r0,  -r1
  2279.        and -w.  The -r  switches  are  used  to  reverse  the  sense  of
  2280.        resolving arbitrary comparisons in the conflict resolution  step.
  2281.        When two equivalent instances are compared the system can  either
  2282.        retain its current best choice, or swap the best choice with  the
  2283.        newly encountered equivalent one.   Whether  or  not  the  system
  2284.        performs the swap when this equivalence arises is  determined  by
  2285.        these switches.  The -r0 switch controls intra-rule  comparisons,
  2286.        i.e. comparisons between instances produced  by  the  same  rule.
  2287.        The -r1 switch  controls  inter-rule  comparisons  -  comparisons
  2288.        between instances produced by different rules.
  2289.             The  -w  switch  works  identically  to   its   compile-time
  2290.        counterpart.  If used, it overrides variable  sizing  of  classes
  2291.        and will also override any setting  created  by  use  of  the  -w
  2292.        compile-time switch.
  2293.  
  2294.  
  2295.        9.5  Interfacing With External Code
  2296.  
  2297.             OPS5c has the  capability  of  interfacing  with  externally
  2298.        written C code.  Actually the type of code that is interfaced  to
  2299.        is irrelevant.  It may be FORTRAN or assembler  as  long  as  the
  2300.        translators output a  common  object  format  understood  by  the
  2301.        linker.  All external programs must use the interface defined  by
  2302.        OPS5c for passing  parameters  and  results  between  the  expert
  2303.        system and the external  routines.   Additionally,  the  external
  2304.        routines must have some  understanding  of  the  data  types  and
  2305.  
  2306.  
  2307.                                     - 35 -
  2308.  
  2309.  
  2310.  
  2311.  
  2312.  
  2313.  
  2314.        OPS5c User's Guide
  2315.  
  2316.  
  2317.        symbol tables used by the OPS5c  system  in  order  to  correctly
  2318.        interface with the expert system.
  2319.  
  2320.        9.5.1  Data Types
  2321.  
  2322.             The  OPS5c  system  has  the  attribute  as   its   simplest
  2323.        unstructured data type.   An  attribute  is  actually  synonymous
  2324.        with the term atom as used in the Lisp programming  language  and
  2325.        both terms will be used  interchangably.   An  atom  is  actually
  2326.        many different  data  types.   An  atom is a structure containing
  2327.        two parts, the storage location for  a  data  type,  and  a  flag
  2328.        indicating what type of data is actually being stored there.   An
  2329.        atom is similar to the concept of a union in the C language,  and
  2330.        in fact is implemented as such: (as defined in o5c.h)
  2331.  
  2332.             typedef union {
  2333.                  float fval;
  2334.                  int ival;
  2335.                  StrID string;
  2336.             } Data;
  2337.  
  2338.             typedef struct attribute {
  2339.                  unsigned char type;
  2340.                  Data data;
  2341.             } Attr;
  2342.  
  2343.        The types currently defined are:
  2344.  
  2345.             AT_FLOAT       :  a floating point value
  2346.             AT_INTEGER     :  an integer value
  2347.             AT_SYMBOL      :  an interned string (see interning below)
  2348.  
  2349.        If the user wished  to  create  an  attribute  to  represent  the
  2350.        constant integer 5, he might code it as:
  2351.  
  2352.             Attr five;
  2353.  
  2354.             five.type = AT_INTEGER;
  2355.             five.data.ival = 5;
  2356.  
  2357.        When coding external functions, the programmer must keep in  mind
  2358.        that attributes  may  be  of  any  type  and  change  their  type
  2359.        dynamically as new values are assigned.   No  assumptions  should
  2360.        be made about  attribute  types.   Library  functions  exist  for
  2361.        comparing  attribute  values.   If  these  are  not   used,   the
  2362.        programmer is responsible for type checking and  coercion.   Most
  2363.        functions that interface with  OPS5c  will  require  pointers  to
  2364.        attributes (typedef'd as  AttrID) as parameters.  It will usually
  2365.        be  necessary  for  external  routines  to  declare   attributes,
  2366.        initialize them correctly, and use the appropriate functions  for
  2367.        comparison, assignment, and retrieval of attribute values.
  2368.  
  2369.  
  2370.  
  2371.  
  2372.  
  2373.                                     - 36 -
  2374.  
  2375.  
  2376.  
  2377.  
  2378.  
  2379.  
  2380.                                                       OPS5c User's Guide
  2381.  
  2382.  
  2383.        9.5.2  The Result Element
  2384.  
  2385.             The   result  element  is  a  global  buffer  used  to  pass
  2386.        parameters between  OPS5c  and  external  routines.   The  result
  2387.        element  (RE) is an array of attributes whose size is that of the
  2388.        largest WME supported by  the  implementation  (128  attributes).
  2389.        Values of attributes may be copied to the RE or copied  from  the
  2390.        RE using a library of functions  known  as  the  dollar  library.
  2391.        This name arises from  the  fact  that  the  Lisp  implementation
  2392.        names functions which operate on the RE using  names  that  start
  2393.        with a dollar sign ($reset, $value, etc.).  Many of  these  names
  2394.        have been kept, where appropriate, but the  functions  are  named
  2395.        dollar_reset, dollar_value, etc. since C  function  names  cannot
  2396.        contain a dollar sign.  Appendix A  describes  the  functions  in
  2397.        the dollar library.
  2398.  
  2399.  
  2400.        9.5.3  Interning and String Spaces
  2401.  
  2402.             The  term  interning comes from the Lisp environment and  is
  2403.        the primary  difference  between  strings and symbols.  A string,
  2404.        as defined by the C programming language, is  simply  a  sequence
  2405.        of characters terminated by a null character.  We often refer  to
  2406.        a string or consider its value to be the  pointer  to  the  first
  2407.        character of the string.  Such  a  pointer  is  used  to  perform
  2408.        comparisons between two  strings  on  a  character  by  character
  2409.        basis to determine equality, inequality, or other  relationships.
  2410.        In OPS5c we are interested in the relationships of  equality  and
  2411.        inequality between attributes with non-numeric  data  types.   If
  2412.        we were to store non-numeric information as strings  and  perform
  2413.        character by character matching, the  testing  process  would  be
  2414.        very slow.  Instead, we form a data structure known as  a  symbol
  2415.        table.  Using such a structure we can  store  strings  (known  as
  2416.        symbols) and look  up  their  pointers  by  a  process  known  as
  2417.        interning.  To intern a string, we call the intern function  with
  2418.        the string as an argument.  The intern  function  will  scan  the
  2419.        symbol table looking for an identical string (i.e.  symbol).   If
  2420.        such a symbol  is  found  then  the  address  of  the  symbol  is
  2421.        returned as the value of the function.   If  no  such  symbol  is
  2422.        found, the string is copied into the symbol table, thus  creating
  2423.        a new symbol, and its address is returned as  the  value  of  the
  2424.        interning function.  This is done for all  non-numeric  attribute
  2425.        values in the system.  The main reason for this is  that  once  a
  2426.        string has been interned, i.e. entered into the symbol table,  we
  2427.        may compare two symbols by comparing their  addresses,  since  if
  2428.        the original strings were identical, then the  interning  process
  2429.        will  return  identical  addresses.   This  greatly   speeds   up
  2430.        comparison of non-numeric data and also results in  less  storage
  2431.        requirements since we store  the  address  as  the  value  of  an
  2432.        interned symbol.
  2433.             As a result, if an external  routine  wishes  to  manipulate
  2434.        symbolic data such that the  OPS5c  inference  engine  can  match
  2435.        properly, attribute values going into and coming out  of  the  RE
  2436.        must be represented as  interned  symbols.   The  dollar  library
  2437.  
  2438.  
  2439.                                     - 37 -
  2440.  
  2441.  
  2442.  
  2443.  
  2444.  
  2445.  
  2446.        OPS5c User's Guide
  2447.  
  2448.  
  2449.        contains a very useful function, dollar_intern, for converting  a
  2450.        string into an interned symbol.
  2451.             To fully interface with the system, the programmer  must  be
  2452.        aware of a more generic library known  as  the  strings  library.
  2453.        Functions in the  strings  library  aid  in  manipulating  values
  2454.        interned as symbols.  The  strings  library  operates  on  string
  2455.        spaces which are equivalent to symbol  tables.   The  distinction
  2456.        and hence reason for different names, is that  the  OPS5c  system
  2457.        keeps several different  string spaces (symbol tables).  The most
  2458.        often used string space is that  for  attribute  values.   It  is
  2459.        called  'attr_values' and  should  be  referenced  as  such  when
  2460.        calling functions in the string library.
  2461.             The functions in the string library are listed  in  Appendix
  2462.        B.   The  most  commonly  used  functions  are   AddString() and  
  2463.        StringAvail().  The AddString() function performs interning in  a
  2464.        string space.  The StringAvail() function simply  tests  for  the
  2465.        existance of a symbol in a  string  space.   Unlike  AddString(),
  2466.        StringAvail() will not add a new symbol  if  it  is  not  already
  2467.        there.  Note that the string library  functions  return  pointers
  2468.        of type String Entry.  The String  Entry  data  type  is  defined
  2469.        below.
  2470.  
  2471.             typedef struct {
  2472.                  HT_Entry_Header link;
  2473.                  StrID str_id;
  2474.             } String_HT_Header;
  2475.  
  2476.             typedef String_HT_Header *StringEntry;
  2477.  
  2478.        Frequently the user will wish to dereference the  StringEntry  to
  2479.        obtain the StrID of the returned  value.   The  StrID  is  not  a
  2480.        string pointer and should be treated as a handle to  the  symbol.
  2481.        The  GetString()  macro  can  be  used  to  return   the   string
  2482.        associated with a StrID.
  2483.             Another  string  space  of  interest  is  'attr_names'.   It
  2484.        contains symbols for all the declared attribute  names  known  by
  2485.        the system.  The programmer should not  attempt  to  add  to  the
  2486.        attr_names string space, only to  read  from  it.   StringEntry's
  2487.        retrieved  from  this  name  space  should  be  cast  to  (struct
  2488.        attr_off *) where:
  2489.  
  2490.             struct attr_off {
  2491.                  String_HT_Header link;
  2492.                  int offset;
  2493.             };
  2494.  
  2495.        Such a pointer can be dereferenced  by  ptr->offset  to  retrieve
  2496.        the  offset  (slot  position  in  the  RE)  associated   with   a
  2497.        particular attribute name.  This is a common occurrance  when  we
  2498.        wish to access values by attribute name which is the most  common
  2499.        method.
  2500.  
  2501.  
  2502.  
  2503.  
  2504.  
  2505.                                     - 38 -
  2506.  
  2507.  
  2508.  
  2509.  
  2510.  
  2511.  
  2512.                                                       OPS5c User's Guide
  2513.  
  2514.  
  2515.        9.5.4  Functions Versus Actions
  2516.  
  2517.             There are two types of  external  code  that  the  user  can
  2518.        interface  to  an  OPS5c  program,  functions  and  actions.  The
  2519.        distinction between these two forms  of  interface  in  the  OPS5
  2520.        language is vague.  Functions must return a single value  in  the
  2521.        result element.  This is  accomplished  with  the  dollar_value()
  2522.        call.  One and only one call to dollar_value() must be made by  a
  2523.        function.  The  OPS5  language  does  not  specify  how  argument
  2524.        passing to functions are implemented.  For  predefined  functions
  2525.        in-line code or calls to routines in  the  run-time  library  are
  2526.        produced.  For user-defined functions, arguments are  passed  via
  2527.        a global array args[] which  is  an  array  of  attribute  values
  2528.        (atoms).  A global  counter,  fargc,  is  used  to  indicate  the
  2529.        number of valid arguments in args[].   This  is  similar  to  the
  2530.        argc and argv[] method of passing command  line  arguments  to  C
  2531.        programs.  Once parameters are loaded into the args[] array,  the
  2532.        external function is called.   A  C  function  integer  argument,
  2533.        which is the number  of  actual  parameters,  is  passed  to  the
  2534.        function.
  2535.             Unlike functions, actions  may  utilize  all  the  functions
  2536.        defined in the dollar library.  An  action  may  return  zero  or
  2537.        more values.  These values are usually  returned  in  the  result
  2538.        element using the dollar_value() function.   Actions  are  passed
  2539.        arguments through the result element.  Before calling the  action
  2540.        the result element is cleared (filled with nil  atoms)  and  then
  2541.        it is filled  with  the  evaluated  pattern  that  comprises  the
  2542.        parameters.  No modification of the result element  is  performed
  2543.        after the action has finished with it.
  2544.             Note that the OPS5  language  specifies  that  all  external
  2545.        functions  and  actions  must  be  declared  with  the   external
  2546.        statement.  In OPS5c this is not a requirement, however,  actions
  2547.        which are not declared using external cannot be called  from  the
  2548.        top-level environment.
  2549.  
  2550.  
  2551.  
  2552.  
  2553.  
  2554.  
  2555.  
  2556.  
  2557.  
  2558.  
  2559.  
  2560.  
  2561.  
  2562.  
  2563.  
  2564.  
  2565.  
  2566.  
  2567.  
  2568.  
  2569.  
  2570.  
  2571.                                     - 39 -
  2572.  
  2573.  
  2574.  
  2575.  
  2576.  
  2577.  
  2578.        OPS5c User's Guide
  2579.  
  2580.  
  2581.        10. References
  2582.  
  2583.        Forgy81
  2584.             Forgy,  Charles  L.  ,  OPS5  User's  Manual, Department  of
  2585.             Computer Science, Carnegie-Mellon University. CMU-CS-81-135
  2586.  
  2587.  
  2588.        Miranker87
  2589.             Miranker,  D.P.,  TREAT: A Better  Match  Algorithm  for  AI
  2590.             Production  Systems:  Long  Version, Artificial Intelligence
  2591.             Laboratory, University of Texas at Austin, Technical  Report
  2592.             AI TR-87-58
  2593.  
  2594.  
  2595.  
  2596.  
  2597.  
  2598.  
  2599.  
  2600.  
  2601.  
  2602.  
  2603.  
  2604.  
  2605.  
  2606.  
  2607.  
  2608.  
  2609.  
  2610.  
  2611.  
  2612.  
  2613.  
  2614.  
  2615.  
  2616.  
  2617.  
  2618.  
  2619.  
  2620.  
  2621.  
  2622.  
  2623.  
  2624.  
  2625.  
  2626.  
  2627.  
  2628.  
  2629.  
  2630.  
  2631.  
  2632.  
  2633.  
  2634.  
  2635.  
  2636.  
  2637.                                     - 40 -
  2638.  
  2639.  
  2640.  
  2641.  
  2642.  
  2643.  
  2644.                                                       OPS5c User's Guide
  2645.  
  2646.  
  2647.        Appendix A - Dollar Library Description
  2648.  
  2649.  
  2650.  
  2651.        /* Possible return value of dollar_litbind() */
  2652.        #define NOT_DEFINED      -1
  2653.  
  2654.  
  2655.        /************************************************************
  2656.        This routine creates a new wme from the result element.
  2657.         ************************************************************/
  2658.        void
  2659.        dollar_assert(class_index)
  2660.        int class_index;
  2661.  
  2662.  
  2663.  
  2664.        /************************************************************
  2665.        This function takes  an  atom  (attribute  id)  and  returns  its
  2666.        integer value.
  2667.         ************************************************************/
  2668.        int
  2669.        dollar_cvan(atom)
  2670.        AttrID atom;
  2671.  
  2672.  
  2673.        /************************************************************
  2674.        This function  takes  an  integer  and  returns  a  numeric  atom
  2675.        (interned).
  2676.         ************************************************************/
  2677.        Attr
  2678.        dollar_cvna(num)
  2679.        int num;
  2680.  
  2681.  
  2682.        /************************************************************
  2683.        This  function  is  used  to  test  the  equality  of  two  atoms
  2684.        (attributes).
  2685.         ************************************************************/
  2686.         BOOLEAN
  2687.        dollar_eql(atom1,atom2)
  2688.        AttrID atom1;
  2689.        AttrID atom2;
  2690.  
  2691.  
  2692.        /************************************************************
  2693.        This function places a float value in the  result  element.   The
  2694.        value of the float is returned.
  2695.         ************************************************************/
  2696.        float
  2697.        dollar_flt_val(value) 
  2698.        float value;
  2699.  
  2700.  
  2701.  
  2702.  
  2703.                                     - 41 -
  2704.  
  2705.  
  2706.  
  2707.  
  2708.  
  2709.  
  2710.        OPS5c User's Guide
  2711.  
  2712.  
  2713.        /************************************************************
  2714.        This function determines if a file of  specified  name  has  been
  2715.        opened for input.
  2716.         ************************************************************/
  2717.        FILE *
  2718.        dollar_ifile(attr)
  2719.        AttrID attr;
  2720.  
  2721.  
  2722.        /************************************************************
  2723.        This function places an integer  value  in  the  result  element.
  2724.        The value of the integer is returned.
  2725.         ************************************************************/
  2726.        int
  2727.        dollar_int_val(value)
  2728.        int value;
  2729.  
  2730.  
  2731.        /************************************************************
  2732.        This function is used to intern a  string  into  the  attr_values
  2733.        string table.
  2734.         ************************************************************/
  2735.         StrID
  2736.        dollar_intern(str)
  2737.        char *str;
  2738.  
  2739.  
  2740.        /************************************************************
  2741.        This function determines if its string argument is  an  attribute
  2742.        name that has been assigned an offset at compile  time.   If  so,
  2743.        the offset is returned.  If not NOT_DEFINED is returned.
  2744.         ************************************************************/
  2745.        int
  2746.        dollar_litbind(str)
  2747.        char *str;
  2748.  
  2749.  
  2750.        /************************************************************
  2751.        This function returns an attibute  (Attr,  not  an  AttrID)  when
  2752.        given an index into the result element
  2753.         ************************************************************/
  2754.        Attr
  2755.        dollar_parameter(index)
  2756.        int index;
  2757.  
  2758.  
  2759.        /************************************************************
  2760.        This function returns a count of the number of  elements  in  the
  2761.        result element.
  2762.         ************************************************************/
  2763.        int
  2764.        dollar_parametercount()
  2765.  
  2766.  
  2767.  
  2768.  
  2769.                                     - 42 -
  2770.  
  2771.  
  2772.  
  2773.  
  2774.  
  2775.  
  2776.                                                       OPS5c User's Guide
  2777.  
  2778.  
  2779.        /************************************************************
  2780.        This routine clears the result element (fills it  with  nil)  and
  2781.        resets the result element index.
  2782.         ************************************************************/
  2783.        void dollar_reset()
  2784.  
  2785.  
  2786.        /************************************************************
  2787.        This function places a string value in  the  result  element.   A
  2788.        StrID must  be  passed.  (See  strings  module.)   The  StrID  is
  2789.        returned as the result.
  2790.         ************************************************************/
  2791.        StrID
  2792.        dollar_str_val(value)
  2793.        StrID value;
  2794.  
  2795.  
  2796.        /************************************************************
  2797.        This predicate determines if an atom (attribute) is symbolic.
  2798.         ************************************************************/
  2799.        BOOLEAN
  2800.        dollar_symbol(x)
  2801.        Attr x;
  2802.  
  2803.  
  2804.        /************************************************************
  2805.        This routine sets the index of the result element.  Indicies  are
  2806.        numbered starting at 1.  The argument passed must be integer.
  2807.         ************************************************************/
  2808.        dollar_tab1(num)
  2809.        int num;
  2810.  
  2811.  
  2812.        /************************************************************
  2813.        Similar to dollar_tab1() above except that  the  argument  passed
  2814.        is an AttrID.  The attribute may be numeric  (integer  or  float)
  2815.        or a numeric string.
  2816.         ************************************************************/
  2817.        void
  2818.        dollar_tab2(attr_id)
  2819.        AttrID attr_id;
  2820.  
  2821.  
  2822.        /************************************************************
  2823.        This routine takes an attribute structure  (not  an  AttrID)  and
  2824.        places it in the result element at  the  current  position.   The
  2825.        pointer is then incremented to the next position.
  2826.         ************************************************************/
  2827.        dollar_value(attr)
  2828.        Attr attr;
  2829.  
  2830.  
  2831.  
  2832.  
  2833.  
  2834.  
  2835.                                     - 43 -
  2836.  
  2837.  
  2838.  
  2839.  
  2840.  
  2841.  
  2842.        OPS5c User's Guide
  2843.  
  2844.  
  2845.        Appendix B - String Library Description
  2846.  
  2847.  
  2848.        /************************************************************
  2849.         * This function "interns" a string and returns its ID code.  In
  2850.         * this implementation version, the ID is a memory address.
  2851.         ************************************************************/
  2852.        StringEntry
  2853.        AddString(str,string_table,struct_size)
  2854.        char *str;
  2855.        HashTable string_table;
  2856.        int struct_size;
  2857.  
  2858.  
  2859.        /************************************************************
  2860.         * This function checks to see if the indicated string already
  2861.         * exists in the specified string table.  If so, the StringEntry
  2862.         * of the string is returned, else NULL is returned.
  2863.         ************************************************************/
  2864.        StringEntry
  2865.        StringAvail(str,string_table)
  2866.        char *str;
  2867.        HashTable string_table;
  2868.  
  2869.  
  2870.        /************************************************************
  2871.         * This is a macro which can be used with a StrID to return the
  2872.         * pointer to the C string representation of the interned
  2873.         * string.
  2874.         ************************************************************/
  2875.        char *
  2876.        GetString(str_id)
  2877.        StrID str_id;
  2878.  
  2879.  
  2880.  
  2881.  
  2882.  
  2883.  
  2884.  
  2885.  
  2886.  
  2887.  
  2888.  
  2889.  
  2890.  
  2891.  
  2892.  
  2893.  
  2894.  
  2895.  
  2896.  
  2897.  
  2898.  
  2899.  
  2900.  
  2901.                                     - 44 -
  2902.  
  2903.  
  2904.  
  2905.  
  2906.  
  2907.  
  2908.                                                       OPS5c User's Guide
  2909.  
  2910.  
  2911.                                      Index
  2912.  
  2913.        //  14, 17-18, 29
  2914.        accept stream  22
  2915.        ACT  2-3, 5-13, 16-24, 26-30, 34-37, 39
  2916.        actions  2-3, 5-7, 12-13, 16-17, 19-20, 24, 26, 29, 34-35, 39
  2917.        AddString()  38
  2918.        alpha memory  7-8, 26, 32
  2919.        amem  7-8
  2920.        atom  2, 10, 17-19, 36, 39, 41, 43
  2921.        Attr  2, 5, 9-18, 20, 29-30, 33, 35-39, 41-43
  2922.        attribute  2, 5, 9-11, 13-18, 20, 29-30, 33, 35-39, 41-43
  2923.        attribute variable  13
  2924.        attribute-value pair  13-14, 20
  2925.        AttrID  36, 41-43
  2926.        attr_names  38
  2927.        attr_values  38, 42
  2928.        call  2, 4-7, 16-19, 21-22, 26, 29-39
  2929.        case  5-7, 10, 16, 24, 34
  2930.        CE  2-43
  2931.        class  2, 4-5, 8-15, 20, 22, 27, 29, 31-33, 35, 41
  2932.        closefile  2, 19, 22-23, 29
  2933.        coercion  10, 33, 36
  2934.        comp.sh  34
  2935.        condition element  2, 5, 13, 15-16, 24
  2936.        conflict resolution  2, 6-7, 9, 24, 27, 31, 33, 35
  2937.        conflict set  6-7, 15-16, 22, 24, 30-31, 33
  2938.        conjuctions  2, 14
  2939.        constant tests  7-8, 25
  2940.        context clause  25, 27
  2941.        contexts  27
  2942.        crlf  21
  2943.        default  2, 19, 22-23, 29-30, 34
  2944.        disjunctions  2, 15
  2945.        dominant instance  31
  2946.        element designator  2, 16-18, 20, 29
  2947.        element variable  2, 16-17, 20-21
  2948.        functions  2-4, 10, 17-18, 21, 23, 29, 33-39
  2949.        heuristic ordering  34
  2950.        incremental matching  6, 8
  2951.        instance  5-8, 15-17, 24-25, 27, 29-31, 33, 35
  2952.        interning  3, 36-38
  2953.        JOIN  7, 34
  2954.        join code  34
  2955.        LEX  24-25, 31, 34
  2956.        LHS  2, 5-7, 10, 12-13, 16-18, 20, 24, 29
  2957.        literal  5, 9-10, 13-15
  2958.        literalize  5, 9-10, 14
  2959.        make  2, 5, 7, 16, 19-21, 24, 26, 29, 33
  2960.        MATCH  4, 6-8, 13-16, 20, 26, 30, 32, 37, 40
  2961.        MEA  4, 6, 8, 13, 15, 17, 21, 24-25, 29, 31
  2962.        modular compilation  33
  2963.        modules  34
  2964.        nil  10, 17, 39, 43
  2965.  
  2966.  
  2967.                                     - 45 -
  2968.  
  2969.  
  2970.  
  2971.  
  2972.  
  2973.  
  2974.        OPS5c User's Guide
  2975.  
  2976.  
  2977.        o5c.h  32, 36
  2978.        offsets  9-10, 17-18, 20
  2979.        openfile  2, 19, 22-23, 29
  2980.        ops5c.lib  32
  2981.        predicates  2, 10, 14, 43
  2982.        quoting  2, 13, 15
  2983.        RE  2-44
  2984.        recency  24
  2985.        remove  2, 6, 15-16, 19-21, 24, 28-31
  2986.        result element  3, 17-18, 37, 39, 41-43
  2987.        RETE  4-5, 7, 9, 13, 18, 20, 29, 32
  2988.        RHS  2, 5-7, 12, 16-20, 22, 24, 29-30, 35
  2989.        rjust  21
  2990.        rule  2, 4-10, 12-16, 19-20, 22, 24-31, 33-35
  2991.        seed ordering  34
  2992.        SELECT  5-7, 15, 24-28, 31, 33-34
  2993.        specificity  24
  2994.        StrID  36, 38, 42-44
  2995.        string space  3, 37-38
  2996.        StringAvail()  38
  2997.        StringEntry  38, 44
  2998.        strings  10, 37-38, 43
  2999.        subtasks  26
  3000.        symbol table  9, 33, 36-38
  3001.        symbols  10, 13-14, 34, 37-38
  3002.        tabto  21
  3003.        time tags  9, 24-25, 27, 29-31
  3004.        top level  2, 13, 19, 22, 29-32
  3005.        trace stream  22
  3006.        TREAT  4-5, 7, 11, 13, 19, 21, 38, 40
  3007.        variable binding tests  7, 25
  3008.        vector attributes  2, 10-11
  3009.        WM  2, 5-11, 13-18, 20-21, 24, 26-27, 29-31, 33, 35, 37, 41
  3010.        WME  6-11, 13-18, 20-21, 24, 26-27, 29-31, 33, 35, 37, 41
  3011.        Working memory  2, 5-7, 9, 15, 17, 21-22, 24, 27, 29-33
  3012.        working memory element  2, 6, 9, 30
  3013.        write stream  22
  3014.        \\  18
  3015.  
  3016.  
  3017.  
  3018.  
  3019.  
  3020.  
  3021.  
  3022.  
  3023.  
  3024.  
  3025.  
  3026.  
  3027.  
  3028.  
  3029.  
  3030.  
  3031.  
  3032.  
  3033.                                     - 46 -
  3034.  
  3035.  
  3036.  
  3037.